forked from townforge/townforge
3757 lines
164 KiB
Python
Executable File
3757 lines
164 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
|
|
|
|
"""Test CC RPC
|
|
"""
|
|
|
|
from framework.daemon import Daemon
|
|
from framework.wallet import Wallet
|
|
|
|
FIRST_CITY_X = 0
|
|
FIRST_CITY_Y = 0
|
|
ITEM_STONE = 1
|
|
ITEM_MEDIUM_STONE = 2
|
|
ITEM_WOOD = 4
|
|
MATERIAL_VARIANT_PLOUGHED_FIELD = 32
|
|
MATERIAL_LOCKED_PINE = 26
|
|
ITEM_LABOUR = 256
|
|
ITEM_FIRST_PATENT = 1024
|
|
ITEM_FIRST_FOOD = ITEM_FIRST_PATENT + 4096
|
|
ITEM_FOOD_VEGETABLES = ITEM_FIRST_FOOD
|
|
ITEM_FOOD_GRAIN = ITEM_FIRST_FOOD + 1
|
|
ITEM_FOOD_MEAT = ITEM_FIRST_FOOD + 2
|
|
NUM_PREDEFINED_ITEMS = ITEM_FIRST_FOOD + 1024
|
|
ITEM_FIRST_USER = NUM_PREDEFINED_ITEMS
|
|
ITEM_LAST_USER = 65536 + 1048576 - 1
|
|
ORIGIN_RESOURCE_RADIUS = 500
|
|
ROLE_AGRICULTURAL = 1
|
|
ROLE_CRAFT = 2
|
|
ROLE_RESIDENTIAL1 = 5
|
|
ROLE_SAWMILL = 11
|
|
ROLE_STONECUTTER = 10
|
|
MAX_DISTANCE_PERCENTAGE = 1600
|
|
MAX_CC_NAME_LENGTH = 64
|
|
account_creation_fee = 100000000
|
|
GAME_UPDATE_FREQUENCY = 360
|
|
BUILD_RATIO_ACTIVE_THRESHOLD_PERCENT = 0
|
|
MIN_TRADE_EXPIRATION = (86400 / 60)
|
|
MIN_RESEARCH_AMOUNT = 10000000
|
|
LABOUR_LAST_RESORT_PRICE = 40000
|
|
STONE_LAST_RESORT_PRICE = 600000
|
|
NEW_ITEM_FEE = 100000000
|
|
DISCOVERY_RESEARCH_EFFICIENCY = 12
|
|
DISCOVERY_RESEARCH_PRODUCTIVITY = 13
|
|
DISCOVERY_RESEARCH_EXPERTISE = 14
|
|
DISCOVERY_RESEARCH_MASTERY = 15
|
|
DISCOVERY_BUCKET_BRIGADE = 31
|
|
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 = 200
|
|
GAME_ACCOUNT = 2
|
|
COINS_ITEM_GROUP = ITEM_FIRST_USER
|
|
COIN_ITEM_SETTLEMENT = COINS_ITEM_GROUP + 1
|
|
COIN_MINTING_FEE = 10000000
|
|
COIN_SMELTING_FEE = 1000000
|
|
COIN_GOLD_CONTENT = 2500000000
|
|
COIN_MINTING_WINDOW = (7 * 86400 / 60)
|
|
NONCE_CANCELLATION_FEE = 10000000
|
|
collectible_coin_type_players = 1
|
|
collectible_coin_type_city = 2
|
|
collectible_coin_type_yearly = 3
|
|
collectible_coin_type_event = 4
|
|
|
|
def assert_exception(f):
|
|
ok = False
|
|
try:
|
|
f()
|
|
except:
|
|
ok = True
|
|
assert ok
|
|
|
|
def RESOURCE_AVAILABILITY_SCALE(x):
|
|
return int((x) * 4)
|
|
|
|
def COIN_TYPE(x):
|
|
return x >> 56
|
|
|
|
def get_gold_content(coin_type):
|
|
if coin_type == collectible_coin_type_players:
|
|
return 20
|
|
if coin_type == collectible_coin_type_city:
|
|
return 10
|
|
if coin_type == collectible_coin_type_yearly:
|
|
return 5
|
|
if coin_type == collectible_coin_type_event:
|
|
return 25
|
|
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
|
|
|
|
class CCTest():
|
|
def run_test(self):
|
|
self.reset()
|
|
self.create()
|
|
state0 = self.get_state()
|
|
self.mine()
|
|
self.recordreorg_root()
|
|
self.check_no_items()
|
|
self.test_get_new_nonces()
|
|
self.test_cc_account_creation()
|
|
self.test_names()
|
|
self.test_cc_transfers()
|
|
self.test_buy_land()
|
|
self.test_buy_items()
|
|
self.test_build()
|
|
self.test_trading()
|
|
self.test_interacting_trades()
|
|
self.test_accrual_trades()
|
|
self.test_trade_third_party_matching()
|
|
self.test_cancel_nonce()
|
|
self.test_giving()
|
|
self.test_discoveries()
|
|
self.test_game_update()
|
|
self.test_revert()
|
|
self.test_custom_items()
|
|
self.test_badges()
|
|
self.test_resize_flag()
|
|
self.test_attributes()
|
|
self.test_hunt()
|
|
self.test_invitation()
|
|
self.test_chat()
|
|
self.test_ignore()
|
|
self.test_minting()
|
|
self.test_farming()
|
|
self.test_cities()
|
|
self.test_reorg()
|
|
self.reset_and_check_states()
|
|
state1 = self.get_state()
|
|
assert state0 == state1, self.get_diff(state0, state1)
|
|
|
|
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 = []
|
|
|
|
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)
|
|
|
|
def generate_blocks(self, address, nblocks, skip_update = False):
|
|
daemon = self.daemon
|
|
res = daemon.get_height()
|
|
height = res.height
|
|
while len(self.states) > 0 and self.states[-1][0]+1 >= height:
|
|
self.states = self.states[0:-1]
|
|
self.states.append((height - 1, self.get_state()))
|
|
res = daemon.generateblocks(address, nblocks)
|
|
if skip_update and (res.height - 1) % GAME_UPDATE_FREQUENCY == 0:
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
def create(self):
|
|
print('Creating wallets')
|
|
seeds = [
|
|
'teardrop owls later width skater gadget different pegs yard ahead onslaught dynamite thorn espionage dwelt rural eels aimless shipped toaster shocking rounded maverick mystery thorn',
|
|
'geek origin industrial payment friendly physics width putty beyond addicted rogue metro midst anvil unplugs tequila efficient feast elapse liquid degrees smuggled also bawled tequila',
|
|
'tidy heron aching outbreak terminal inorganic nexus umpire economics auctions hope soapy hive vigilant hunter tadpoles hippo southern observant rabbits asked vector gimmick godfather heron',
|
|
'aimless zesty juvenile hedgehog sash eden inflamed faxed abbey piloted silk gigantic affair snout guarded inquest utmost tunnel remedy sighting otherwise alley illness jubilee gigantic',
|
|
'journal vitals technical dying dice taken evicted essential pepper dented psychic vaults oatmeal pairing wrong request damp rugged buffet lids bias pouch ladder leisure rugged',
|
|
]
|
|
self.wallet = [None] * len(seeds)
|
|
self.pkeys = [None] * len(seeds)
|
|
for i in range(len(seeds)):
|
|
self.wallet[i] = Wallet(idx = i)
|
|
# close the wallet if any, will throw if none is loaded
|
|
try: self.wallet[i].close_wallet()
|
|
except: pass
|
|
res = self.wallet[i].restore_deterministic_wallet(seed = seeds[i])
|
|
ok = False
|
|
try: res = self.wallet[i].cc_get_info()
|
|
except: ok = True
|
|
assert ok
|
|
self.wallet[i].set_daemon('127.0.0.1:18182')
|
|
self.daemon = Daemon(idx = 2)
|
|
|
|
global FIRST_CITY_X
|
|
global FIRST_CITY_Y
|
|
res = self.daemon.cc_get_city(0)
|
|
FIRST_CITY_X = res.ox
|
|
FIRST_CITY_Y = res.oy
|
|
|
|
def mine(self):
|
|
print("Mining many blocks")
|
|
daemon = self.daemon
|
|
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
|
|
blocks_mined = 0
|
|
for data in [
|
|
['TF1MMEY5v2dN49XKNCKCdBqmTMM6GdZZA5UBbDgTewaUd3c2jDazN5yKrG1BBHX3UyPqKD9hrh3DpPTDmWiCmsuRpePT1MTaPxm', 15], # wallet[0]
|
|
['TF1MM5mG6EQkz899pz3uFDR6D2EUowvZWw75hcE6TETrodxHXSKFK6u3SRtEQzJ6epc5HD85dEgYF7xhgBtoFjMHKNFAEuGg1Lk', 15], # wallet[1]
|
|
['TF1MMCHHDFKYSQ1DkLWskTxU2fC7jtZLwcATXHP3uvJo4dV757dtGwUE9ZL6SE9DJhxrvzThAsG4drVmAPHzEvh6TCq19AbzTo4', 330], # wallet[3]
|
|
['TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 500], # 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 at game start')
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
if 'count' in res:
|
|
for x in res.count:
|
|
assert x == 0
|
|
|
|
def test_get_new_nonces(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing getting new nonces")
|
|
|
|
assert_exception(lambda self: 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')
|
|
assert len(res.fee_list) == 1
|
|
fee0 = res.fee_list[0]
|
|
|
|
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')
|
|
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)
|
|
balance[1] += 25000000 - res.fee_list[0]
|
|
cc_balance[1] -= 25000000
|
|
|
|
res = self.wallet[2].cc_deposit(amount = 500000000, name = 'wallet 2')
|
|
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])
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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(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(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(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(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(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 test_buy_items(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing buying items")
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
item_counts = res.counts
|
|
|
|
res = self.wallet[2].refresh()
|
|
res = self.wallet[2].cc_get_info()
|
|
cc_balance = res.cc_balance
|
|
account_id = res.account_id
|
|
|
|
res = daemon.cc_get_account(account_id)
|
|
assert not 'item_balances' in res or len(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, a.amount)
|
|
|
|
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_build(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing building")
|
|
|
|
flag_id = 2
|
|
|
|
# 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)
|
|
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)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# can't set 0 economic power
|
|
ok = False
|
|
try: self.wallet[2].cc_building_settings(flag_id, 1, 0)
|
|
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)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# ok
|
|
res = self.wallet[2].cc_building_settings(flag_id, 1, 100, name = 'test building')
|
|
assert len(res.tx_hash) == 64
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# not our flag
|
|
ok = False
|
|
try: self.wallet[0].cc_build(flag_id, 0, 0, 1, 1, block_data = [0, ITEM_STONE], encoded = True)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# good
|
|
res = self.wallet[2].cc_build(flag_id, 0, 0, 1, 1, block_data = [0, ITEM_STONE], encoded = True)
|
|
assert len(res.tx_hash) == 64
|
|
|
|
# out of the flag
|
|
ok = False
|
|
try: self.wallet[2].cc_build(flag_id, 252, 252, 1, 1, block_data = [0, ITEM_STONE], encoded = True)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# out of the flag 2
|
|
ok = False
|
|
try: self.wallet[2].cc_build(flag_id, 0, 0, 254, 254, block_data = [0, ITEM_STONE], encoded = True)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# empty data
|
|
ok = False
|
|
try: self.wallet[2].cc_build(flag_id, 0, 0, 2, 2, block_data = [], encoded = True)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# too few blocks
|
|
ok = False
|
|
try: self.wallet[2].cc_build(flag_id, 0, 0, 2, 2, block_data = [1, 0], encoded = True)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# invalid block type
|
|
ok = False
|
|
try: self.wallet[2].cc_build(flag_id, 0, 0, 1, 1, block_data = [0, 250], encoded = True)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# check tile state - should be just one
|
|
res = self.wallet[2].cc_get_info()
|
|
account_id = res.account_id
|
|
|
|
res = daemon.cc_get_flag(flag_id, 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):
|
|
expected_tiles = []
|
|
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, 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):
|
|
expected_tiles = []
|
|
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_WOOD], encoded = False, build_height = 2)
|
|
assert len(res.tx_hash) == 64
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_flag(flag_id, 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):
|
|
expected_tiles = []
|
|
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_WOOD]
|
|
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, 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
|
|
assert_exception(lambda self: 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}]))
|
|
|
|
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.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
|
|
trade = res.bids[0]
|
|
assert trade.nonce == bid_1_2_80_a_nonce or trade.nonce == bid_1_2_80_b_nonce
|
|
assert not trade.mined # not matched, stays in the txpool
|
|
|
|
# test filtering
|
|
res2 = daemon.cc_get_order_book(True, False)
|
|
assert res2.bids == res.bids
|
|
assert not 'offers' in res2
|
|
res2 = daemon.cc_get_order_book(False, True)
|
|
assert not 'bids' in res2
|
|
assert res2.offers == res.offers
|
|
res2 = daemon.cc_get_order_book(True, True, type=[234])
|
|
assert not 'offers' in res2
|
|
assert not 'bids' in res2
|
|
res2 = daemon.cc_get_order_book(True, True, id=[234])
|
|
assert not 'offers' in res2
|
|
assert not 'bids' in res2
|
|
res2 = daemon.cc_get_order_book(True, True, type=[1])
|
|
assert res2.offers == res.offers
|
|
assert res2.bids == res.bids
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
expected_balances[2] -= offer_1_5_80_fee
|
|
expected_balances[1] -= bid_1_2_80_b_fee
|
|
|
|
matched_amount = 2
|
|
matched_price = 80
|
|
expected_balances[1] -= matched_amount * matched_price
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], 1, matched_amount)
|
|
expected_balances[2] += matched_amount * matched_price
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], 1, -matched_amount)
|
|
|
|
# the offer should still be around, with 2 used and 3 left, and the last bid is gone
|
|
res = daemon.cc_get_order_book(True, True)
|
|
assert len(res.offers) == 1
|
|
assert len(res.bids) == 1
|
|
trade = res.offers[0]
|
|
assert trade.nonce == offer_1_5_80_nonce
|
|
assert trade.account == account_id[2]
|
|
assert trade.mined # but mined, and partially matched
|
|
assert trade.amount == 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 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.mined
|
|
assert trade.amount == 2
|
|
trade = res.bids[0]
|
|
assert trade.nonce == bid_1_2_80_a_nonce
|
|
assert trade.mined
|
|
assert trade.amount == 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 == 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 == 1
|
|
|
|
# we can't match more than one unmined tx
|
|
ok = False
|
|
try: self.wallet[0].cc_trade_item(True, 1, 4, 100, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': offer_1_3_85_nonce, 'amount': 3}, {'nonce': offer_1_2_90_nonce, 'amount': 1}], cost = 85 * 3 + 90 * 1)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# we can't grab only part of one while leaving some for another
|
|
ok = False
|
|
try: self.wallet[0].cc_trade_item(True, 1, 4, 100, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': offer_1_5_80_nonce, 'amount': 1}, {'nonce': offer_1_2_90_nonce, 'amount': 1}], cost = 85 + 90)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# nibble at offer_1_3_85_nonce so it gets mined
|
|
res = self.wallet[0].cc_trade_item(True, 1, 1, 100, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': offer_1_3_85_nonce, 'amount': 1}], cost = 85)
|
|
expected_balances[0] -= res.fee
|
|
expected_balances[0] -= 85
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], 1, 1)
|
|
expected_balances[1] -= offer_1_3_85_fee
|
|
expected_balances[1] += 85
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], 1, -1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# match several txes, once of them partially
|
|
res = self.wallet[0].cc_trade_item(True, 1, 5, 100, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': offer_1_5_80_nonce, 'amount': 2}, {'nonce': offer_1_2_90_nonce, 'amount': 2}, {'nonce': offer_1_3_85_nonce, 'amount': 1}], cost = 2 * 80 + 2 * 90 + 1 * 85)
|
|
expected_balances[0] -= res.fee
|
|
expected_balances[0] -= 2 * 80 + 2 * 90 + 1 * 85
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], 1, 5)
|
|
expected_balances[2] -= offer_1_2_90_fee
|
|
expected_balances[2] += 2 * 80 + 2 * 90
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], 1, -4)
|
|
expected_balances[1] += 1 * 85
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], 1, -1)
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
# expiration too high
|
|
ok = False
|
|
try: self.wallet[2].cc_trade_item(False, 1, 1, 80, 0, 0, 0, 821500)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# expiration in the past
|
|
ok = False
|
|
try: self.wallet[2].cc_trade_item(False, 1, 1, 80, 0, 0, 0, 10)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# expiration too low
|
|
res = daemon.get_height()
|
|
height = res.height
|
|
ok = False
|
|
try: self.wallet[2].cc_trade_item(False, 1, 1, 80, 0, 0, 0, res.height + 100)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# current orders
|
|
# 2 sells 1 at 100
|
|
# 1 sells 1 at 85
|
|
# 1 buys 1 at 80
|
|
|
|
res = daemon.cc_get_order_book(True, True)
|
|
assert len(res.offers) == 2
|
|
trade = res.offers[0]
|
|
assert trade.nonce == offer_1_3_85_nonce
|
|
assert trade.mined
|
|
assert trade.account == account_id[1]
|
|
assert trade.amount == 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.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 == 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.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.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
expected_balances[1] = 1000000000
|
|
|
|
self.wallet[1].refresh()
|
|
res = daemon.cc_get_account(account_id[1])
|
|
assert res.balance == expected_balances[1]
|
|
|
|
# matching a tx from an account that does not have the blocks anymore
|
|
res = self.wallet[1].cc_trade_item(False, 1, 1, 90, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000)
|
|
assert len(res.tx_hash) == 64
|
|
nonce = res.cc_nonce
|
|
assert nonce > 0
|
|
expected_balances[1] -= res.fee
|
|
res = self.wallet[0].cc_trade_item(True, 1, 1, 90, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': nonce, 'amount': 1}], cost = 90)
|
|
assert len(res.tx_hash) == 64
|
|
expected_balances[0] -= res.fee
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
expected_balances[1] += 90
|
|
expected_balances[0] -= 90
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], 1, -1)
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], 1, 1)
|
|
|
|
ok = False
|
|
try: self.wallet[2].cc_trade_item(True, 1, 1, 85, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': offer_1_3_85_nonce, 'amount': 1}], cost = 85)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
# sell a flag we do not have
|
|
res = daemon.cc_get_account(account_id[2])
|
|
assert len(res.flags) >= 1
|
|
flag_id = res.flags[0]
|
|
assert flag_id > 0
|
|
|
|
ok = False
|
|
try: self.wallet[1].cc_trade_flag(False, flag_id, 1000, 0, 0, 0, 0, expiration = base_height + MIN_TRADE_EXPIRATION + 1000)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# sell a flag we do have
|
|
res = self.wallet[2].cc_trade_flag(False, flag_id, 1000, 0, 0, 0, 0, expiration = base_height + MIN_TRADE_EXPIRATION + 1000)
|
|
assert len(res.tx_hash) == 64
|
|
flag_nonce = res.cc_nonce
|
|
assert flag_nonce > 0
|
|
expected_balances[2] -= res.fee
|
|
|
|
# try to buy a different one
|
|
ok = False
|
|
try: self.wallet[1].cc_trade_flag(True, flag_id + 1, 1000, 0, 0, 0, 0, expiration = base_height + MIN_TRADE_EXPIRATION + 1000, match_nonce = flag_nonce, cost = 1000)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# buy it
|
|
res = self.wallet[1].cc_trade_flag(True, flag_id, 1001, 0, 0, 0, 0, expiration = base_height + MIN_TRADE_EXPIRATION + 1000, match_nonce = flag_nonce, cost = 1000)
|
|
assert len(res.tx_hash) == 64
|
|
expected_balances[1] -= res.fee
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
expected_balances[2] += 1000
|
|
expected_balances[1] -= 1000
|
|
|
|
res = daemon.cc_get_account(account_id[2])
|
|
assert flag_id not in res.flags
|
|
res = daemon.cc_get_account(account_id[1])
|
|
assert len(res.flags) >= 1
|
|
assert flag_id in res.flags
|
|
|
|
# cannot buy twice
|
|
for i in [0, 1]:
|
|
ok = False
|
|
try: self.wallet[1].cc_trade_flag(True, flag_id, 1001, 0, 0, 0, 0, expiration = base_height + MIN_TRADE_EXPIRATION + 1000, match_nonce = flag_nonce, cost = 1000)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
|
|
def test_interacting_trades(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing interacting trades")
|
|
res = daemon.get_height()
|
|
base_height = res.height
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
item_counts = res.counts
|
|
|
|
account_id = [None, None, None]
|
|
for i in range(3):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id[i] = res.account_id
|
|
|
|
# sell a flag, two others buy it
|
|
res = daemon.cc_get_account(account_id[1])
|
|
assert len(res.flags) >= 1
|
|
flag_id = res.flags[0]
|
|
assert flag_id > 0
|
|
|
|
res = self.wallet[1].cc_trade_flag(False, flag_id, 1000, 0, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000)
|
|
assert len(res.tx_hash) == 64
|
|
flag_nonce = res.cc_nonce
|
|
assert flag_nonce > 0
|
|
|
|
res = self.wallet[0].cc_trade_flag(True, flag_id, 1000, 0, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, match_nonce = flag_nonce, cost = 1000)
|
|
assert len(res.tx_hash) == 64
|
|
|
|
ok = False
|
|
try: self.wallet[2].cc_trade_flag(True, flag_id, 1000, 0, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, match_nonce = flag_nonce, cost = 1000)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# sell blocks, many people try to buy, overflowing the sold amount
|
|
daemon.get_connections()
|
|
for i in range(3):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
res = daemon.cc_get_account(res.account_id)
|
|
res = self.wallet[2].cc_trade_item(False, 1, 10, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000)
|
|
nonce = res.cc_nonce
|
|
res = self.wallet[1].cc_trade_item(True, 1, 8, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': nonce, 'amount': 8}], cost = 8*80)
|
|
res = self.wallet[0].cc_trade_item(True, 1, 4, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': nonce, 'amount': 4}], cost = 4*80)
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
for i in range(3):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
|
|
daemon.flush_txpool()
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
|
|
def test_giving(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing giving")
|
|
res = daemon.get_height()
|
|
base_height = res.height
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
item_counts = res.counts
|
|
|
|
expected_balances = [None, None, None]
|
|
expected_item_balances = [None, None, None]
|
|
account_id = [None, None, None]
|
|
account_public_key = [None, None, None]
|
|
for i in range(3):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id[i] = res.account_id
|
|
account_public_key[i] = res.cc_pkey
|
|
res = daemon.cc_get_account(account_id[i])
|
|
expected_balances[i] = res.balance
|
|
expected_item_balances[i] = []
|
|
if 'item_balances' in res:
|
|
for e in res.item_balances:
|
|
expected_item_balances[i] = self.add_item(expected_item_balances[i], e.type, e.amount)
|
|
|
|
res = self.wallet[1].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 8}, {'type': ITEM_WOOD, 'amount': 4}])
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_STONE, 8)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_WOOD, 4)
|
|
item_counts[ITEM_STONE] += 8
|
|
item_counts[ITEM_WOOD] += 4
|
|
|
|
# first try to give more
|
|
ok = False
|
|
try: self.wallet[1].cc_give(account_public_key[0], [{'type': ITEM_STONE, 'amount': 9}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
ok = False
|
|
try: self.wallet[1].cc_give(account_public_key[0], [{'type': ITEM_WOOD, 'amount': 5}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
ok = False
|
|
try: self.wallet[1].cc_give(account_public_key[0], [{'type': ITEM_LABOUR, 'amount': 100}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
ok = False
|
|
try: self.wallet[1].cc_give(account_public_key[0], [{'type': ITEM_STONE, 'amount': 1}, {'type': ITEM_WOOD, 'amount': 5}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
self.wallet[1].cc_give(account_public_key[0], [{'type': ITEM_STONE, 'amount': 3}, {'type': ITEM_WOOD, 'amount': 2}])
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_STONE, -3)
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], ITEM_STONE, 3)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_WOOD, -2)
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], ITEM_WOOD, 2)
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
|
|
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
|
|
|
|
# they should now be matchable
|
|
self.wallet[2].cc_trade_flag(True, flag_id, 998, 0, 0, 0, 0, expiration = base_height + MIN_TRADE_EXPIRATION + 1000, match_nonce = flag_nonce, cost = 998)
|
|
self.wallet[2].cc_trade_item(True, ITEM_LABOUR, 1, 88, 0, 0, 0, expiration = base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': labour_nonce, 'amount': 1}], cost = 88)
|
|
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 2)
|
|
|
|
for i in range(3):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
|
|
daemon.flush_txpool()
|
|
|
|
def test_trade_third_party_matching(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing trade third party matching")
|
|
res = daemon.get_height()
|
|
base_height = res.height
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
item_counts = res.counts
|
|
|
|
account_id = [None, None, None]
|
|
expected_balances = [None, None, None]
|
|
expected_item_balances = [None, None, None]
|
|
for i in range(3):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id[i] = res.account_id
|
|
res = daemon.cc_get_account(account_id[i])
|
|
expected_balances[i] = res.balance
|
|
expected_item_balances[i] = []
|
|
if 'item_balances' in res:
|
|
for e in res.item_balances:
|
|
expected_item_balances[i] = self.add_item(expected_item_balances[i], e.type, e.amount)
|
|
|
|
# give wallet 0 some more money to buy test stuff
|
|
res = self.wallet[2].cc_transfer(self.pkeys[0], amount = 150000000)
|
|
assert len(res.fee_list) == 1
|
|
expected_balances[2] -= res.fee_list[0]
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
expected_balances[2] -= 150000000
|
|
expected_balances[0] += 150000000
|
|
|
|
res = self.wallet[0].cc_buy_items(entries = [{'type': ITEM_LABOUR, 'amount': 25}, {'type': ITEM_STONE, 'amount': 10}])
|
|
expected_balances[0] -= res.fee
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], ITEM_LABOUR, 25)
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], ITEM_STONE, 10)
|
|
expected_balances[0] -= 25 * LABOUR_LAST_RESORT_PRICE + 10 * STONE_LAST_RESORT_PRICE
|
|
item_counts[ITEM_LABOUR] += 25
|
|
item_counts[ITEM_STONE] += 10
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
# a sell and a buy at the same price, without specifying a match
|
|
res = self.wallet[0].cc_trade_item(False, ITEM_LABOUR, 5, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 100)
|
|
txid_0 = res.tx_hash
|
|
nonce_0 = res.cc_nonce
|
|
fee_0 = res.fee
|
|
res = self.wallet[1].cc_trade_item(True, ITEM_LABOUR, 2, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 100)
|
|
txid_1_0 = res.tx_hash
|
|
nonce_1_0 = res.cc_nonce
|
|
fee_1_0 = res.fee
|
|
res = self.wallet[1].cc_trade_item(True, ITEM_LABOUR, 2, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 100)
|
|
txid_1_1 = res.tx_hash
|
|
nonce_1_1 = res.cc_nonce
|
|
fee_1_1 = res.fee
|
|
res = self.wallet[1].cc_trade_item(True, ITEM_LABOUR, 2, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 100)
|
|
txid_1_2 = res.tx_hash
|
|
nonce_1_2 = res.cc_nonce
|
|
fee_1_2 = res.fee
|
|
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# they should still be in the txpool
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert txid_0 in res.tx_hashes
|
|
assert txid_1_0 in res.tx_hashes
|
|
assert txid_1_1 in res.tx_hashes
|
|
assert txid_1_2 in res.tx_hashes
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
# match too much
|
|
ok = False
|
|
try: res = self.wallet[2].cc_match(match = nonce_0, matches = [{'nonce': nonce_1, 'amount': 6}])
|
|
except: ok = True
|
|
assert ok
|
|
ok = False
|
|
try: res = self.wallet[2].cc_match(match = nonce_1, matches = [{'nonce': nonce_0, 'amount': 6}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# match 0 amount
|
|
ok = False
|
|
try: res = self.wallet[2].cc_match(match = nonce_0, matches = [{'nonce': nonce_1, 'amount': 0}])
|
|
except: ok = True
|
|
assert ok
|
|
ok = False
|
|
try: res = self.wallet[2].cc_match(match = nonce_1, matches = [{'nonce': nonce_0, 'amount': 0}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# match one
|
|
res = self.wallet[2].cc_match(match = nonce_0, matches = [{'nonce': nonce_1_0, 'amount': 2}])
|
|
txid_M = res.tx_hash
|
|
fee_M = res.fee
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 3)
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], ITEM_LABOUR, -2)
|
|
expected_balances[0] += 2 * 80
|
|
expected_balances[0] -= fee_0
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_LABOUR, 2)
|
|
expected_balances[1] -= 2 * 80
|
|
expected_balances[1] -= fee_1_0
|
|
expected_balances[2] -= fee_M
|
|
|
|
# they should not be in the txpool anymore, except for the two unused bids
|
|
res = daemon.get_transaction_pool_hashes()
|
|
tx_hashes = res.tx_hashes if 'tx_hashes' in res else []
|
|
assert not txid_M in tx_hashes
|
|
assert not txid_0 in tx_hashes
|
|
assert not txid_1_0 in tx_hashes
|
|
assert txid_1_1 in tx_hashes
|
|
assert txid_1_2 in tx_hashes
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
# we can still match some of it
|
|
res = self.wallet[2].cc_match(match = nonce_1_1, cost = 2 * 80, matches = [{'nonce': nonce_0, 'amount': 2}])
|
|
txid_M = res.tx_hash
|
|
fee_M = res.fee
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 3)
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], ITEM_LABOUR, -2)
|
|
expected_balances[0] += 2 * 80
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_LABOUR, 2)
|
|
expected_balances[1] -= 2 * 80
|
|
expected_balances[1] -= fee_1_1
|
|
expected_balances[2] -= fee_M
|
|
|
|
# they should not be in the txpool anymore, except the last one
|
|
res = daemon.get_transaction_pool_hashes()
|
|
tx_hashes = res.tx_hashes if 'tx_hashes' in res else []
|
|
assert not txid_M in tx_hashes
|
|
assert not txid_0 in tx_hashes
|
|
assert not txid_1_0 in tx_hashes
|
|
assert not txid_1_1 in tx_hashes
|
|
assert txid_1_2 in tx_hashes
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
# match too much for what is left (1)
|
|
ok = False
|
|
try: res = self.wallet[2].cc_match(match = nonce_0, matches = [{'nonce': nonce_1, 'amount': 2}])
|
|
except: ok = True
|
|
assert ok
|
|
ok = False
|
|
try: res = self.wallet[2].cc_match(match = nonce_1, matches = [{'nonce': nonce_0, 'amount': 2}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
|
|
daemon.flush_txpool()
|
|
|
|
def test_cancel_nonce(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing nonce cancellation")
|
|
|
|
account_id = [None, None, None]
|
|
expected_balances = [None, None, None]
|
|
expected_item_balances = [None, None, None]
|
|
account_public_key = [None, None, None]
|
|
for i in range(3):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id[i] = res.account_id
|
|
account_public_key[i] = res.cc_pkey
|
|
res = daemon.cc_get_account(account_id[i])
|
|
expected_balances[i] = res.balance
|
|
expected_item_balances[i] = []
|
|
if 'item_balances' in res:
|
|
for e in res.item_balances:
|
|
expected_item_balances[i] = self.add_item(expected_item_balances[i], e.type, e.amount)
|
|
|
|
daemon.flush_txpool()
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
|
|
res = self.wallet[2].cc_trade_item(False, ITEM_LABOUR, 5, 80, 0, 0, 0, height + MIN_TRADE_EXPIRATION + 100)
|
|
txid = res.tx_hash
|
|
fee = res.fee
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert txid in res.tx_hashes
|
|
res = daemon.get_transactions([txid], get_cc_data = True)
|
|
assert len(res.txs) == 1
|
|
e = res.txs[0]
|
|
assert e.tx_hash == txid
|
|
assert e.in_pool
|
|
nonce = e.cc_nonce
|
|
|
|
# not mined yet
|
|
res = daemon.cc_is_nonce_used(nonce)
|
|
assert not res.used
|
|
|
|
# other accounts may cancel, but this will not prevent the trade from being mined
|
|
res = self.wallet[1].cc_cancel_nonce(nonce)
|
|
expected_balances[1] -= res.fee
|
|
expected_balances[1] -= NONCE_CANCELLATION_FEE
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_is_nonce_used(nonce)
|
|
assert res.used
|
|
assert res.accounts == [account_id[1]]
|
|
assert res.txid == '0' * 64
|
|
|
|
assert_exception(lambda self: self.wallet[1].cc_cancel_nonce(nonce))
|
|
|
|
res = self.wallet[0].cc_cancel_nonce(nonce)
|
|
expected_balances[0] -= res.fee
|
|
expected_balances[0] -= NONCE_CANCELLATION_FEE
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_is_nonce_used(nonce)
|
|
assert res.used
|
|
assert sorted(res.accounts) == sorted([account_id[1], account_id[0]])
|
|
assert res.txid == '0' * 64
|
|
|
|
res = self.wallet[1].cc_trade_item(True, ITEM_LABOUR, 5, 80, 0, 0, 0, height + MIN_TRADE_EXPIRATION + 10, matches = [{'nonce': nonce, 'amount': 5}], cost = 80*5)
|
|
expected_balances[1] -= res.fee
|
|
expected_balances[2] -= fee
|
|
expected_balances[1] -= 80 * 5
|
|
expected_balances[2] += 80 * 5
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_LABOUR, 5)
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_LABOUR, -5)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert 'tx_hashes' not in res or not txid in res.tx_hashes
|
|
|
|
# now points to the mined tx, the other accounts' cancellations are still there
|
|
res = daemon.cc_is_nonce_used(nonce)
|
|
assert res.used
|
|
assert sorted(res.accounts) == sorted([account_id[1], account_id[0]])
|
|
assert res.txid == txid
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i], "balance diff: " + str(res.balance - expected_balances[i])
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
# again, with actual cancellation of an unmined tx
|
|
res = self.wallet[2].cc_trade_item(False, ITEM_LABOUR, 5, 80, 0, 0, 0, height + MIN_TRADE_EXPIRATION + 100)
|
|
txid = res.tx_hash
|
|
fee = res.fee
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert txid in res.tx_hashes
|
|
res = daemon.get_transactions([txid], get_cc_data = True)
|
|
assert len(res.txs) == 1
|
|
e = res.txs[0]
|
|
assert e.tx_hash == txid
|
|
assert e.in_pool
|
|
nonce = e.cc_nonce
|
|
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert txid in res.tx_hashes
|
|
|
|
res = daemon.cc_is_nonce_used(nonce)
|
|
assert not res.used
|
|
|
|
res = self.wallet[2].cc_cancel_nonce(nonce)
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[2] -= NONCE_CANCELLATION_FEE
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_is_nonce_used(nonce)
|
|
assert res.used
|
|
assert res.accounts == [account_id[2]]
|
|
assert res.txid == '0' * 64
|
|
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert 'tx_hashes' not in res or not txid in res.tx_hashes
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
# and cancellation of a partially matched tx
|
|
res = self.wallet[2].cc_trade_item(False, ITEM_LABOUR, 5, 80, 0, 0, 0, height + MIN_TRADE_EXPIRATION + 100)
|
|
txid = res.tx_hash
|
|
fee = res.fee
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert txid in res.tx_hashes
|
|
res = daemon.get_transactions([txid], get_cc_data = True)
|
|
assert len(res.txs) == 1
|
|
e = res.txs[0]
|
|
assert e.tx_hash == txid
|
|
assert e.in_pool
|
|
nonce = e.cc_nonce
|
|
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert txid in res.tx_hashes
|
|
|
|
res = daemon.cc_is_nonce_used(nonce)
|
|
assert not res.used
|
|
assert not 'accounts' in res or len(res.accounts) == 0
|
|
|
|
res = self.wallet[1].cc_trade_item(True, ITEM_LABOUR, 1, 80, 0, 0, 0, height + MIN_TRADE_EXPIRATION + 10, matches = [{'nonce': nonce, 'amount': 1}], cost = 80*1)
|
|
expected_balances[1] -= res.fee
|
|
expected_balances[2] -= fee
|
|
expected_balances[1] -= 80 * 1
|
|
expected_balances[2] += 80 * 1
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_LABOUR, 1)
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_LABOUR, -1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert 'tx_hashes' not in res or not txid in res.tx_hashes
|
|
|
|
# the trade tx is mined, but further matches can be prevented
|
|
assert_exception(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
|
|
assert_exception(lambda self: self.wallet[0].cc_cancel_nonce(nonce))
|
|
# nor ourselves
|
|
assert_exception(lambda self: self.wallet[2].cc_cancel_nonce(nonce))
|
|
|
|
# keep balances as we found them
|
|
res = self.wallet[1].cc_give(account_public_key[2], [{'type': ITEM_LABOUR, 'amount': 6}])
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
def test_game_update(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing game update")
|
|
|
|
res = daemon.cc_get_new_flag_cost(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(FIRST_CITY_X - 180, FIRST_CITY_Y - 180, FIRST_CITY_X - 180 + 64 - 1, FIRST_CITY_Y - 180 + 64 - 1)
|
|
cost = res.cost
|
|
res = self.wallet[2].cc_buy_land(FIRST_CITY_X - 180, FIRST_CITY_Y - 180, FIRST_CITY_X - 180 + 64 - 1, FIRST_CITY_Y - 180 + 64 - 1)
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = self.wallet[2].refresh()
|
|
res = self.wallet[2].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
flag0_id = res.flags[-1]
|
|
assert flag0_id > 0
|
|
flag1_id = res.flags[-2]
|
|
assert flag1_id > 0
|
|
|
|
res = self.wallet[2].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 2943}, {'type': ITEM_WOOD, 'amount': 2150}, {'type': ITEM_LABOUR, 'amount': 50000}])
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = self.wallet[2].cc_building_settings(flag0_id, ROLE_AGRICULTURAL, 100)
|
|
assert len(res.tx_hash) == 64
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = self.wallet[2].cc_building_settings(flag1_id, ROLE_AGRICULTURAL, 100)
|
|
assert len(res.tx_hash) == 64
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = self.wallet[2].refresh()
|
|
|
|
# buildings start off inactive
|
|
res = daemon.cc_get_flag(flag0_id)
|
|
assert not res.active
|
|
res = daemon.cc_get_flag(flag1_id)
|
|
assert not res.active
|
|
|
|
res = self.wallet[2].cc_build(flag0_id, 0, 0, 8, 8, block_data = [0x80 | (64-1), ITEM_WOOD], encoded = True)
|
|
assert len(res.tx_hash) == 64
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = self.wallet[2].refresh()
|
|
|
|
# mine enough to pass one update
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
|
|
# the building with enough built blocks should now be active, but the other should not be, unless BUILD_RATIO_ACTIVE_THRESHOLD_PERCENT is 0
|
|
res = daemon.cc_get_flag(flag0_id)
|
|
assert res.active
|
|
res = daemon.cc_get_flag(flag1_id)
|
|
assert res.active == (BUILD_RATIO_ACTIVE_THRESHOLD_PERCENT == 0)
|
|
|
|
def get_state(self):
|
|
daemon = self.daemon
|
|
state = {}
|
|
res = daemon.get_info()
|
|
state['info.height'] = res.height
|
|
res = daemon.cc_get_cities()
|
|
state['cities'] = res
|
|
num_cities = len(res.cities)
|
|
for i in range(num_cities):
|
|
try:
|
|
res = daemon.cc_get_city(i)
|
|
state['city_' + str(i)] = res
|
|
res = daemon.cc_get_special_events(i)
|
|
state['city_' + str(i) + '_special_events'] = res
|
|
except:
|
|
pass
|
|
try:
|
|
res = daemon.get_shares(i)
|
|
state['city_' + str(i) + '_shares'] = res
|
|
except:
|
|
pass
|
|
res = daemon.cc_get_accounts()
|
|
state['accounts'] = res.accounts
|
|
accounts = [x.id for x in res.accounts]
|
|
for i in accounts:
|
|
res = daemon.cc_get_account(i)
|
|
state['account_' + str(i)] = res
|
|
res = daemon.cc_get_flags()
|
|
state['flags'] = res.flags if 'flags' in res else None
|
|
flags = [x.id for x in res.flags] if 'flags' in res else []
|
|
for i in flags:
|
|
res = daemon.cc_get_flag(i)
|
|
state['flag_' + str(i)] = res
|
|
res = daemon.cc_get_last_update_events()
|
|
state['events'] = res
|
|
state['events']['top_hash'] = None
|
|
# do not include orders, those include txpool state so not conensus
|
|
res = daemon.cc_get_discoveries()
|
|
state['discoveries'] = res
|
|
res = daemon.cc_get_custom_items()
|
|
state['custom_items'] = res
|
|
try:
|
|
res = daemon.cc_get_badge([])
|
|
state['event_badges'] = res
|
|
except:
|
|
pass
|
|
res = daemon.cc_get_attributes()
|
|
state['attributes'] = res
|
|
res = daemon.cc_get_bonuses(accounts)
|
|
state['bonuses'] = res.bonuses
|
|
res = daemon.cc_get_badge_totals()
|
|
state['badge_totals'] = res.entries
|
|
ids = [x for x in range(NUM_PREDEFINED_ITEMS)]
|
|
res = daemon.cc_get_item_count(ids)
|
|
state['item_counts'] = res.count if 'count' in res else None
|
|
res = daemon.cc_get_used_nonces()
|
|
state['used_nonces'] = res.nonces if 'nonces' in res else None
|
|
return state
|
|
|
|
def remove_height(self, state):
|
|
new_state = state.copy()
|
|
del new_state['info.height']
|
|
return new_state
|
|
|
|
def remove_used_nonces(self, state):
|
|
new_state = state.copy()
|
|
del new_state['used_nonces']
|
|
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()
|
|
if mined:
|
|
assert self.remove_height(state0) != self.remove_height(state1), self.get_diff(state0, state1)
|
|
else:
|
|
assert self.remove_height(state0) == self.remove_height(state1), self.get_diff(state0, state1)
|
|
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()
|
|
assert self.remove_used_nonces(state1) == self.remove_used_nonces(state3), self.get_diff(self.remove_used_nonces(state1), self.remove_used_nonces(state3))
|
|
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))
|
|
|
|
# deposit on an existing account
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_deposit(amount = 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 * 1500}, {'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 + 16 - 1, FIRST_CITY_Y - 100 + 16 - 1, discounted = True))
|
|
|
|
# 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
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_building_settings(flag_id, ROLE_RESIDENTIAL1, 200, 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_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_name = res.name
|
|
flag_active = res.active
|
|
flag_budget = res.budget
|
|
assert 'tiles' in res
|
|
flag_tiles = res.tiles
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_demolish(flag_id, width = flag_width, height = flag_height, role = flag_role, economic_power = flag_economic_power, repair = flag_repair, construction_height = flag_construction_height, name = flag_name, active = flag_active, budget = flag_budget, tiles = flag_tiles))
|
|
|
|
# research
|
|
res = daemon.cc_get_discoveries()
|
|
assert res.discoveries[DISCOVERY_BUCKET_BRIGADE].name == "Bucket brigade"
|
|
difficulty = res.discoveries[DISCOVERY_BUCKET_BRIGADE].difficulty
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_research(DISCOVERY_BUCKET_BRIGADE, difficulty * 5))
|
|
|
|
# new item
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_new_item(8, "Test item for testing revert", False, False, 0, "primary desc", "secondary desc"))
|
|
|
|
# dividend (monetary and item)
|
|
res = daemon.cc_get_custom_items()
|
|
assert len(res.items_) > 0
|
|
custom_item_id = res.items_[-1].id
|
|
assert res.items_[-1].amount == 8
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_dividend(custom_item_id, 0, 100))
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_dividend(custom_item_id, ITEM_STONE, 16))
|
|
|
|
# new event badge
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_event_badge(0, "Test badge for testing revert", "Event badge desc", [{"account_id": 4, "from_level": 0, "to_level": 2}]))
|
|
|
|
# assign event badge
|
|
from_timestamp = 0
|
|
res = daemon.cc_get_account(4)
|
|
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": 4, "from_level": 2, "to_level": 3, "from_timestamp": from_timestamp}]))
|
|
|
|
# destroy items
|
|
res = daemon.cc_get_custom_items()
|
|
item_id = res.items_[-1].id
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_destroy_items(item_id, 2))
|
|
|
|
# define attribute
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_define_attribute('Test attribute', 'foo'))
|
|
|
|
# increase attribute
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[0].cc_increase_attribute(1, 1))
|
|
|
|
# dice roll
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_dice_roll("x", 10, 20))
|
|
|
|
# hunt
|
|
res = daemon.cc_get_city(0)
|
|
moose = res.moose
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_hunt(target = 0, city = 0, population = moose), redo = False)
|
|
bears = res.bears
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_hunt(target = 1, city = 0, population = bears), redo = False)
|
|
|
|
# destroy_flag
|
|
res = self.wallet[3].cc_buy_land(FIRST_CITY_X + 500, FIRST_CITY_Y, FIRST_CITY_X + 500 + 8 - 1, FIRST_CITY_Y + 8 - 1)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = self.wallet[3].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
flag_id = res.flags[-1]
|
|
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))
|
|
|
|
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
|
|
|
|
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
|
|
expected_balances[2] -= NEW_ITEM_FEE
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_FIRST_USER + existing_items, 100)
|
|
|
|
res = self.wallet[2].cc_new_item(30, "Test item 2", False, False, 0, "primary desc", "secondary desc")
|
|
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
|
|
expected_balances[2] -= NEW_ITEM_FEE
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_FIRST_USER + existing_items + 1, 30)
|
|
|
|
# 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)
|
|
|
|
# money dividend
|
|
res = self.wallet[2].cc_dividend(ITEM_FIRST_USER + existing_items + 1, 0, 100 * 30)
|
|
expected_balances[2] -= res.fee
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
expected_balances[2] -= 100 * 5
|
|
expected_balances[0] += 100 * 3
|
|
expected_balances[1] += 100 * 2
|
|
|
|
# item dividend
|
|
res = self.wallet[2].cc_dividend(ITEM_FIRST_USER + existing_items + 1, ITEM_LABOUR, 5 * 30 + 29)
|
|
expected_balances[2] -= res.fee
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_LABOUR, -5 * 5)
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], ITEM_LABOUR, 5 * 3)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_LABOUR, 5 * 2)
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
|
|
print('Testing item destruction')
|
|
|
|
# testing destruction
|
|
res = self.wallet[2].cc_destroy_items(ITEM_FIRST_USER + existing_items + 1, 3)
|
|
expected_balances[2] -= res.fee
|
|
res = self.wallet[2].cc_destroy_items(ITEM_WOOD, 2)
|
|
expected_balances[2] -= res.fee
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 2)
|
|
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
|
|
|
|
# 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 - 3]
|
|
|
|
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
|
|
# 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
|
|
assert_exception(lambda self: self.wallet[2].cc_new_item(30, "Group", True, False, 0, "primary desc", "secondary desc"))
|
|
|
|
# group with group to a non custom item
|
|
assert_exception(lambda self: self.wallet[2].cc_new_item(0, "Group", True, False, ITEM_WOOD, "primary desc", "secondary desc"))
|
|
|
|
res = self.wallet[2].cc_new_item(0, "Group", True, False, 0, "primary desc", "secondary desc")
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[2] -= NEW_ITEM_FEE
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_custom_items()
|
|
e = res.items_[-1]
|
|
assert e.id >= ITEM_FIRST_USER and e.id <= ITEM_LAST_USER
|
|
assert e.is_group
|
|
assert not e.is_public
|
|
assert e.group == 0
|
|
assert e.user_data == 0
|
|
group_id = e.id
|
|
|
|
res = self.wallet[2].cc_new_item(1, "Group member 1", False, False, group_id, "primary desc", "secondary desc")
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[2] -= NEW_ITEM_FEE
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_FIRST_USER + existing_items + 3, 1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_custom_items()
|
|
e = res.items_[-1]
|
|
assert e.id >= ITEM_FIRST_USER and e.id <= ITEM_LAST_USER
|
|
assert not e.is_group
|
|
assert not e.is_public
|
|
assert e.group == group_id
|
|
group_member_1_id = e.id
|
|
assert e.id == ITEM_FIRST_USER + existing_items + 3
|
|
res = self.wallet[2].cc_new_item(1, "Group member 2", False, False, group_id, "primary desc", "secondary desc")
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[2] -= NEW_ITEM_FEE
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_FIRST_USER + existing_items + 4, 1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_custom_items()
|
|
e = res.items_[-1]
|
|
assert e.id >= ITEM_FIRST_USER and e.id <= ITEM_LAST_USER
|
|
assert not e.is_group
|
|
assert not e.is_public
|
|
assert e.group == group_id
|
|
assert e.user_data == 0
|
|
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(range(ITEM_FIRST_USER + existing_items, ITEM_FIRST_USER + existing_items + 4 + 1))
|
|
assert res.counts == [100, 30 - 3, 2, 1, 1]
|
|
|
|
res = self.wallet[2].cc_new_item(0, "Subgroup", True, False, group_id, "primary desc", "secondary desc")
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[2] -= NEW_ITEM_FEE
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_custom_items()
|
|
e = res.items_[-1]
|
|
assert e.id >= ITEM_FIRST_USER and e.id <= ITEM_LAST_USER
|
|
assert e.is_group
|
|
assert not e.is_public
|
|
assert e.group == group_id
|
|
assert e.user_data == 0
|
|
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
|
|
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
|
|
subgroup_member_2_id = e.id
|
|
|
|
# wrong owner
|
|
assert_exception(lambda self: self.wallet[1].cc_new_item(1, "Invalid", False, False, group_id, "primary desc", "secondary desc"))
|
|
|
|
# groups is not a group
|
|
assert_exception(lambda self: 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(range(ITEM_FIRST_USER + existing_items, ITEM_FIRST_USER + existing_items + 7 + 1))
|
|
assert res.counts == [100, 30 - 3, 14, 1, 1, 12, 4, 8]
|
|
|
|
# others can add to public groups
|
|
res = self.wallet[2].cc_new_item(0, "Public group", True, True, group_id, "primary desc", "secondary desc")
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[2] -= NEW_ITEM_FEE
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_custom_items()
|
|
e = res.items_[-1]
|
|
assert e.id >= ITEM_FIRST_USER and e.id <= ITEM_LAST_USER
|
|
assert e.is_group
|
|
assert e.is_public
|
|
assert e.group == group_id
|
|
assert e.user_data == 0
|
|
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
|
|
assert e.group == public_group_id
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
res = daemon.cc_get_item_count(range(ITEM_FIRST_USER + existing_items, ITEM_FIRST_USER + existing_items + 7 + 3))
|
|
assert res.counts == [100, 30 - 3, 18, 1, 1, 12, 4, 8, 4, 4]
|
|
|
|
def test_badges(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing badges")
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
item_counts = res.counts
|
|
|
|
account_id = [None, None, None]
|
|
for i in range(3):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id[i] = res.account_id
|
|
|
|
self.wallet[3].cc_event_badge(0, "Some test badge", "Event badge desc", [{"account_id": account_id[0], "from_level": 0, "to_level": 2}, {"account_id": account_id[2], "from_level": 0, "to_level": 1}])
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.get_height()
|
|
height = res.height
|
|
res = daemon.cc_get_badge([])
|
|
badge = res.badges[-1]
|
|
assert badge.id > 0
|
|
assert badge.name == "Some test badge"
|
|
assert badge.description == "Event badge desc"
|
|
badge_id = badge.id
|
|
res = daemon.cc_get_account(account_id[0])
|
|
assert res.badges[-1].type == badge_id
|
|
assert res.badges[-1].level == 2
|
|
assert res.badges[-1].timestamp == height - 1
|
|
res = daemon.cc_get_account(account_id[2])
|
|
assert res.badges[-1].type == badge_id
|
|
assert res.badges[-1].level == 1
|
|
assert res.badges[-1].timestamp == height - 1
|
|
|
|
from_timestamp = [0, 0, 0]
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
for e in res.badges if 'badges' in res else []:
|
|
if e.type == badge_id:
|
|
from_timestamp[i] = e.timestamp
|
|
|
|
self.wallet[3].cc_event_badge(badge_id, "", "", [{"account_id": account_id[0], "from_level": 2, "to_level": 4, "from_timestamp": from_timestamp[0]}, {"account_id": account_id[1], "from_level": 0, "to_level": 2, "from_timestamp": from_timestamp[1]}])
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_account(account_id[0])
|
|
assert res.badges[-1].type == badge_id
|
|
assert res.badges[-1].level == 4
|
|
assert res.badges[-1].timestamp == height
|
|
res = daemon.cc_get_account(account_id[2])
|
|
assert res.badges[-1].type == badge_id
|
|
assert res.badges[-1].level == 1
|
|
assert res.badges[-1].timestamp == height - 1
|
|
res = daemon.cc_get_account(account_id[1])
|
|
assert res.badges[-1].type == badge_id
|
|
assert res.badges[-1].level == 2
|
|
assert res.badges[-1].timestamp == height
|
|
|
|
# invalid: does not change
|
|
ok = False
|
|
try: self.wallet[3].cc_event_badge(badge_id, "", "", [{"account_id": account_id[0], "from_level": 4, "to_level": 4, "from_timestamp": from_timestamp[0]}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# invalid: wrong from
|
|
ok = False
|
|
try: self.wallet[3].cc_event_badge(badge_id, "", "", [{"account_id": account_id[0], "from_level": 3, "to_level": 5, "from_timestamp": from_timestamp[0]}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# invalid: goes down
|
|
ok = False
|
|
try: self.wallet[3].cc_event_badge(badge_id, "", "", [{"account_id": account_id[0], "from_level": 4, "to_level": 3, "from_timestamp": from_timestamp[0]}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# invalid: goes too high
|
|
ok = False
|
|
try: self.wallet[3].cc_event_badge(badge_id, "", "", [{"account_id": account_id[0], "from_level": 4, "to_level": 6, "from_timestamp": from_timestamp[0]}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# invalid: both id and name
|
|
ok = False
|
|
try: self.wallet[3].cc_event_badge(badge_id, "not empty", "", [{"account_id": account_id[0], "from_level": 4, "to_level": 5, "from_timestamp": from_timestamp[0]}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# invalid: not an event badge
|
|
ok = False
|
|
try: self.wallet[3].cc_event_badge(1, "", "", [{"account_id": account_id[0], "from_level": 4, "to_level": 5, "from_timestamp": from_timestamp[0]}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# invalid: unallocated event badge
|
|
ok = False
|
|
try: self.wallet[3].cc_event_badge(4096 + 1024, "", "", [{"account_id": account_id[0], "from_level": 4, "to_level": 5, "from_timestamp": from_timestamp[0]}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# valid: new event badge, no recipients
|
|
self.wallet[3].cc_event_badge(0, "Badge with no recipients", "desc", [])
|
|
|
|
# invalid: bad from timestamp
|
|
ok = False
|
|
try: self.wallet[3].cc_event_badge(badge_id, "", "", [{"account_id": account_id[0], "from_level": 4, "to_level": 5, "from_timestamp": 999999}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
|
|
def test_resize_flag(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing resizing flags")
|
|
|
|
res = daemon.cc_get_new_flag_cost(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(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(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(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(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(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(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(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(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(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)
|
|
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()
|
|
|
|
print("Testing invalid names")
|
|
for name in ["", "a\0", " ", "a ", " a", "1", "a&", "\xff\xff", "a" * (MAX_CC_NAME_LENGTH + 1), u"いちりゅう", "\0f", u"いちりゅういちりゅういちりゅういちりゅういちりゅう"]:
|
|
ok = False
|
|
try:
|
|
res = self.wallet[2].cc_deposit(amount = 100000000, name = name)
|
|
except:
|
|
ok = True
|
|
assert ok
|
|
|
|
print("Testing conflicting names")
|
|
res = self.wallet[2].cc_deposit(amount = 100000000, name = 'Foo')
|
|
txid = res.tx_hash_list[0]
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = self.wallet[2].refresh()
|
|
res = self.wallet[2].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
assert res.name == "Foo", res
|
|
for name in ["foo", "foO", "FOO"]:
|
|
ok = False
|
|
try:
|
|
res = self.wallet[3].cc_deposit(amount = 100000000, name = name)
|
|
except:
|
|
ok = True
|
|
assert ok
|
|
daemon.pop_blocks(1)
|
|
daemon.flush_txpool(txid)
|
|
self.wallet[2].rescan_blockchain()
|
|
|
|
def test_attributes(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing attributes")
|
|
|
|
res = daemon.cc_get_attributes()
|
|
assert len(res.attributes) == 1 # from revert test
|
|
|
|
ok = False
|
|
try: res = self.wallet[3].cc_define_attribute('', 'desc')
|
|
except: ok = True
|
|
assert ok
|
|
|
|
description = 'The quality of that which is evanescent (duh)'
|
|
res = self.wallet[3].cc_define_attribute('Evanescence', description)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_attributes()
|
|
assert len(res.attributes) == 2
|
|
assert res.attributes[1].name == 'Evanescence'
|
|
assert res.attributes[1].description == description
|
|
|
|
ok = False
|
|
try: res = self.wallet[3].cc_define_attribute('Evanescence', description)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
res = self.wallet[2].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
for e in res.attributes if 'attributes' in res else []:
|
|
assert e.value == 0
|
|
|
|
self.wallet[2].cc_increase_attribute(2, 1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
ok = False
|
|
try: res = self.wallet[3].cc_increase_attribute(3, 1)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
ok = False
|
|
try: res = self.wallet[3].cc_increase_attribute(2, 5)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
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_hunt(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing hunt")
|
|
|
|
res = self.wallet[2].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
moose_killed = res.moose_killed
|
|
bears_killed = res.bears_killed
|
|
starting_meat = 0
|
|
for x in res.item_balances:
|
|
if x['type'] == ITEM_FOOD_MEAT:
|
|
starting_meat = x['amount']
|
|
|
|
res = daemon.cc_get_city(0)
|
|
population = res.moose
|
|
starting_moose = res.moose
|
|
starting_bears = res.bears
|
|
|
|
# bad population
|
|
ok = False
|
|
try: self.wallet[2].cc_hunt(target = 0, city = 0, population = population + 1)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# bad city
|
|
ok = False
|
|
try: self.wallet[2].cc_hunt(target = 0, city = 9, population = population)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# bad target
|
|
ok = False
|
|
try: self.wallet[2].cc_hunt(target = 2, city = 0, population = population)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
self.wallet[2].cc_hunt(target = 0, city = 0, population = population)
|
|
|
|
# only one at a time
|
|
ok = False
|
|
try: self.wallet[2].cc_hunt(target = 1, city = 0, population = population)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_account(account_id)
|
|
assert res.moose_killed > moose_killed
|
|
moose_killed = res.moose_killed
|
|
assert bears_killed == res.bears_killed
|
|
meat = 0
|
|
for x in res.item_balances:
|
|
if x['type'] == ITEM_FOOD_MEAT:
|
|
meat = x['amount']
|
|
assert meat > starting_meat
|
|
|
|
starting_meat = meat
|
|
res = daemon.cc_get_city(0)
|
|
population = res.bears
|
|
self.wallet[2].cc_hunt(target = 1, city = 0, population = population)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_account(account_id)
|
|
assert moose_killed == res.moose_killed
|
|
assert res.bears_killed > bears_killed
|
|
bears_killed = res.bears_killed
|
|
meat = 0
|
|
for x in res.item_balances:
|
|
if x['type'] == ITEM_FOOD_MEAT:
|
|
meat = x['amount']
|
|
assert meat > starting_meat
|
|
|
|
res = daemon.cc_get_city(0)
|
|
new_moose = res.moose
|
|
assert new_moose == starting_moose - moose_killed
|
|
new_bears = res.bears
|
|
assert new_bears == starting_bears - bears_killed
|
|
|
|
# mine enough to pass one update
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
|
|
# check regeneration
|
|
res = daemon.cc_get_city(0)
|
|
assert res.moose > new_moose
|
|
assert res.bears > new_bears
|
|
|
|
# with lower population
|
|
res = daemon.cc_get_city(0)
|
|
old_moose = res.moose
|
|
self.wallet[2].cc_hunt(target = 0, city = 0, population = 100)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_city(0)
|
|
new_moose = res.moose
|
|
assert new_moose < old_moose
|
|
|
|
def test_invitation(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing invitations")
|
|
|
|
res = self.wallet[2].cc_create_invitation(amount = 250000000)
|
|
invitation = res.invitation
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
ok = False
|
|
try: res = self.wallet[4].cc_get_info()
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# can't redeem if we already have an account
|
|
ok = False
|
|
try: self.wallet[0].cc_redeem_account(invitation, "invited account 2")
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# bad name
|
|
ok = False
|
|
try: self.wallet[4].cc_redeem_account(invitation, "")
|
|
except: ok = True
|
|
assert ok
|
|
|
|
self.wallet[4].cc_redeem_account(invitation, "invited account")
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
self.wallet[4].refresh()
|
|
res = self.wallet[4].cc_get_info()
|
|
account_id = res.account_id
|
|
assert account_id != 0
|
|
res = 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
|
|
|
|
def test_chat(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing chat")
|
|
|
|
# bad color
|
|
ok = False
|
|
try: self.wallet[2].cc_chat("foo", color = 200)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
res = self.wallet[2].cc_chat("foo", color = 2)
|
|
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
|
|
res = daemon.cc_get_flag(1)
|
|
assert not res.ignore
|
|
res = self.wallet[3].cc_ignore(type = IGNORE_FLAG, id = [1], ignore = True)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_flag(1)
|
|
assert res.ignore
|
|
res = self.wallet[3].cc_ignore(type = IGNORE_FLAG, id = [1], ignore = False)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_flag(1)
|
|
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")
|
|
|
|
expected_balances = [None, None, None]
|
|
expected_item_balances = [None, None, None]
|
|
account_id = [None, None, None]
|
|
for i in range(3):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id[i] = res.account_id
|
|
res = daemon.cc_get_account(account_id[i])
|
|
expected_balances[i] = res.balance
|
|
expected_item_balances[i] = []
|
|
if 'item_balances' in res:
|
|
for e in res.item_balances:
|
|
expected_item_balances[i] = self.add_item(expected_item_balances[i], e.type, e.amount)
|
|
|
|
# there should be a preexisting coin, without any instances
|
|
res = daemon.cc_get_custom_items([COINS_ITEM_GROUP, COIN_ITEM_SETTLEMENT])
|
|
assert len(res.items_) == 2
|
|
assert res.items_[0].id == COINS_ITEM_GROUP
|
|
assert res.items_[0].group == 0
|
|
assert res.items_[0].is_group
|
|
assert res.items_[0].amount == 0
|
|
assert res.items_[0].creator == GAME_ACCOUNT
|
|
assert res.items_[0].creation_height == 0
|
|
assert res.items_[1].id == COIN_ITEM_SETTLEMENT
|
|
assert res.items_[1].group == COINS_ITEM_GROUP
|
|
assert not res.items_[1].is_group
|
|
assert res.items_[1].amount == 0
|
|
assert res.items_[1].creator == GAME_ACCOUNT
|
|
assert res.items_[1].creation_height == 0
|
|
|
|
res = daemon.cc_get_custom_items()
|
|
n_existing_custom_items = len(res.items_)
|
|
|
|
# but it's too late to mint any
|
|
assert_exception(lambda self: self.wallet[2].cc_mint(COIN_ITEM_SETTLEMENT, 1))
|
|
|
|
# or smelt any either
|
|
assert_exception(lambda self: self.wallet[2].cc_smelt(COIN_ITEM_SETTLEMENT, 1))
|
|
|
|
# can't mint the group either
|
|
assert_exception(lambda self: self.wallet[2].cc_mint(COINS_ITEM_GROUP, 1))
|
|
|
|
# create a fresh one, and a new coin item
|
|
res = self.wallet[3].cc_new_item(0, "Test coin", False, False, COINS_ITEM_GROUP, "primary desc", "secondary desc")
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 2)
|
|
res = self.wallet[3].cc_new_item(1, "Test non-coin", False, False, 0, "primary desc", "secondary desc")
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 2)
|
|
|
|
res = daemon.cc_get_custom_items()
|
|
assert n_existing_custom_items + 2 == len(res.items_)
|
|
test_coin = res.items_[-2]
|
|
assert test_coin.group == COINS_ITEM_GROUP
|
|
test_non_coin = res.items_[-1]
|
|
assert test_non_coin.group == 0
|
|
|
|
# we can mint the coin, but not the coin group
|
|
res = self.wallet[2].cc_mint(test_coin.id, 3)
|
|
gold_content = get_gold_content(COIN_TYPE(test_coin.user_data))
|
|
assert gold_content > 0
|
|
expected_balances[2] -= res.fee + COIN_MINTING_FEE * 3 + gold_content * 100000000 * 3
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], test_coin.id, 3)
|
|
assert_exception(lambda self: 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]
|
|
|
|
# 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
|
|
assert_exception(lambda self: self.wallet[2].cc_smelt(test_coin.id, 2))
|
|
|
|
# can't smelt the group either
|
|
assert_exception(lambda self: self.wallet[2].cc_smelt(test_non_coin.id, 1))
|
|
|
|
# wallet 1 can't smelt anything
|
|
assert_exception(lambda self: 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 three days
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', COIN_MINTING_WINDOW)
|
|
|
|
# can't mint anymore
|
|
assert_exception(lambda self: 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)
|
|
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(FIRST_CITY_X - 350, FIRST_CITY_Y - 350, FIRST_CITY_X - 350 + 60 - 1, FIRST_CITY_Y - 350 + 60 - 1)
|
|
res = self.wallet[2].cc_buy_land(FIRST_CITY_X - 350, FIRST_CITY_Y - 350, FIRST_CITY_X - 350 + 60 - 1, FIRST_CITY_Y - 350 + 60 - 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': 1800}, {'type': ITEM_WOOD, 'amount': 1}, {'type': ITEM_LABOUR, 'amount': 1}])
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = self.wallet[2].cc_building_settings(flag_id, ROLE_AGRICULTURAL, 100, name = 'test building')
|
|
assert len(res.tx_hash) == 64
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_calendar()
|
|
if res.vegetables_sowing_season:
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', res.blocks_till_vegetables_sowing_season_end)
|
|
res = daemon.cc_get_calendar()
|
|
assert not res.vegetables_sowing_season
|
|
|
|
res = daemon.cc_get_flag(flag_id)
|
|
if res.repair < 500000:
|
|
self.wallet[1].cc_repair([flag_id, 1000000 - res.repair])
|
|
|
|
assert_exception(lambda self: self.wallet[2].cc_sow(flag_id, CROP_NONE))
|
|
assert_exception(lambda self: self.wallet[2].cc_sow(flag_id, CROP_VEGETABLES))
|
|
assert_exception(lambda self: self.wallet[2].cc_sow(flag_id, CROP_GRAIN))
|
|
assert_exception(lambda self: self.wallet[2].cc_sow(flag_id, 255))
|
|
|
|
assert_exception(lambda self: self.wallet[2].cc_harvest(flag_id, CROP_NONE, 0, 0))
|
|
|
|
# get into sowing season
|
|
res = daemon.cc_get_calendar()
|
|
if not res.vegetables_sowing_season:
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', res.blocks_till_vegetables_sowing_season_start)
|
|
res = daemon.cc_get_calendar()
|
|
assert res.vegetables_sowing_season
|
|
|
|
res = daemon.cc_get_flag(flag_id)
|
|
if res.repair < 500000:
|
|
self.wallet[1].cc_repair([flag_id, 1000000 - res.repair])
|
|
|
|
# now we can sow
|
|
assert_exception(lambda self: self.wallet[2].cc_sow(flag_id, CROP_NONE))
|
|
assert_exception(lambda self: 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
|
|
assert_exception(lambda self: self.wallet[2].cc_sow(flag_id, CROP_VEGETABLES))
|
|
assert_exception(lambda self: 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
|
|
assert_exception(lambda self: self.wallet[2].cc_harvest(flag_id, CROP_VEGETABLES, sow_height, vegetables_nutrients))
|
|
|
|
# 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)
|
|
if res.repair < 500000:
|
|
self.wallet[1].cc_repair([flag_id, 1000000 - res.repair])
|
|
|
|
# still cannot sow
|
|
assert_exception(lambda self: self.wallet[2].cc_sow(flag_id, CROP_VEGETABLES))
|
|
assert_exception(lambda self: self.wallet[2].cc_sow(flag_id, CROP_GRAIN))
|
|
|
|
# but we can harvest now
|
|
assert_exception(lambda self: self.wallet[2].cc_harvest(flag_id - 1, CROP_VEGETABLES, sow_height, vegetables_nutrients))
|
|
assert_exception(lambda self: self.wallet[2].cc_harvest(flag_id, CROP_GRAIN, sow_height, vegetables_nutrients))
|
|
assert_exception(lambda self: self.wallet[2].cc_harvest(flag_id, CROP_VEGETABLES, sow_height - 1, vegetables_nutrients))
|
|
assert_exception(lambda self: self.wallet[2].cc_harvest(flag_id, CROP_VEGETABLES, sow_height + 1, vegetables_nutrients))
|
|
assert_exception(lambda self: self.wallet[2].cc_harvest(flag_id, CROP_VEGETABLES, sow_height, vegetables_nutrients - 1))
|
|
|
|
res = self.wallet[2].cc_harvest(flag_id, CROP_VEGETABLES, sow_height, vegetables_nutrients)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# not twice
|
|
assert_exception(lambda self: self.wallet[2].cc_harvest(flag_id, CROP_VEGETABLES, sow_height, vegetables_nutrients))
|
|
|
|
# and we can't sow right afterwards either
|
|
assert_exception(lambda self: self.wallet[2].cc_sow(flag_id, CROP_VEGETABLES))
|
|
assert_exception(lambda self: self.wallet[2].cc_sow(flag_id, CROP_GRAIN))
|
|
|
|
# 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[1].cc_repair([flag_id, 1000000 - res.repair])
|
|
|
|
# vegetables nutrients should have recovered somewhat, but not fully, grain nutrients should not have gone past 100
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.vegetables_nutrients < 100
|
|
assert res.vegetables_nutrients > vegetables_nutrients
|
|
assert res.grain_nutrients == 100
|
|
|
|
def test_cities(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing cities")
|
|
|
|
# get a lot more money
|
|
self.generate_blocks('TF1MM5mG6EQkz899pz3uFDR6D2EUowvZWw75hcE6TETrodxHXSKFK6u3SRtEQzJ6epc5HD85dEgYF7xhgBtoFjMHKNFAEuGg1Lk', 60)
|
|
for i in range(20):
|
|
self.generate_blocks('TF1MM5mG6EQkz899pz3uFDR6D2EUowvZWw75hcE6TETrodxHXSKFK6u3SRtEQzJ6epc5HD85dEgYF7xhgBtoFjMHKNFAEuGg1Lk', 100)
|
|
self.wallet[1].refresh()
|
|
res = self.wallet[1].cc_deposit(amount = 250000000000)
|
|
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': 1500000}, {'type': ITEM_WOOD, 'amount': 15000000}, {'type': ITEM_LABOUR, 'amount': 50000000}])
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
farms = []
|
|
buildings = []
|
|
for i in range(25):
|
|
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_RESIDENTIAL1][i % 5]
|
|
if role == ROLE_AGRICULTURAL:
|
|
farms.append(last_flag)
|
|
buildings.append(last_flag)
|
|
self.wallet[1].cc_building_settings(last_flag, role, 100)
|
|
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 True:
|
|
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, 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
|
|
self.wallet[1].cc_harvest(flag, CROP_VEGETABLES, sow_height, vegetables_nutrients)
|
|
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
|
|
self.wallet[1].cc_harvest(flag, CROP_GRAIN, sow_height, grain_nutrients)
|
|
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
|
|
|
|
# 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', blocks)
|
|
|
|
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 == 9
|
|
assert res.specializations == 0
|
|
assert res.max_level == 0
|
|
assert res.moose == NUM_STARTING_MOOSE
|
|
assert res.bears == NUM_STARTING_BEARS
|
|
|
|
ur_ox = res.ox
|
|
ur_oy = res.oy
|
|
|
|
# build in this new city
|
|
self.wallet[1].cc_buy_land(ur_ox + i * 128, ur_oy + 1500, ur_ox + i * 128 + 127, ur_oy + 1500 + 127)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
res = daemon.cc_get_account(account_id)
|
|
flag = res.flags[-1]
|
|
self.wallet[1].cc_building_settings(flag, ROLE_AGRICULTURAL, 100)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
|
|
def test_discoveries(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing discoveries")
|
|
|
|
res = daemon.cc_get_discoveries()
|
|
assert (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 = MIN_RESEARCH_AMOUNT * 100
|
|
res = self.wallet[2].cc_research(discovery, amount)
|
|
assert len(res.tx_hash) == 64
|
|
budget += amount
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1, True)
|
|
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
|
|
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
|
|
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 = MIN_RESEARCH_AMOUNT * 1000
|
|
res = self.wallet[2].cc_research(discovery, amount)
|
|
assert len(res.tx_hash) == 64
|
|
budget += amount
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1, True)
|
|
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 test_reorg(self):
|
|
daemon = self.daemon
|
|
second_daemon = Daemon(idx = 3)
|
|
third_daemon = Daemon(idx = 4)
|
|
|
|
print('Testing reorg')
|
|
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
|
|
state0 = self.get_state()
|
|
|
|
assert len(self.reorg_root_hash) == 64
|
|
res = daemon.get_info()
|
|
assert len(res.top_block_hash) == 64
|
|
assert res.top_block_hash != self.reorg_root_hash
|
|
original_top_block = res.top_block_hash
|
|
res = daemon.getblockheaderbyheight(self.reorg_root_height + 1)
|
|
first_orphaned_block_hash = res.block_header.hash
|
|
assert len(first_orphaned_block_hash) == 64
|
|
assert not res.block_header.orphan_status
|
|
assert res.block_header.height == self.reorg_root_height + 1
|
|
|
|
# ensure synced
|
|
print('Syncing second and third daemons')
|
|
daemon.out_peers(8)
|
|
daemon.in_peers(8)
|
|
second_daemon.out_peers(8)
|
|
second_daemon.in_peers(8)
|
|
third_daemon.out_peers(8)
|
|
third_daemon.in_peers(8)
|
|
loops = 100
|
|
while True:
|
|
res0 = daemon.get_info()
|
|
res1 = second_daemon.get_info()
|
|
res2 = third_daemon.get_info()
|
|
if res0.top_block_hash == res1.top_block_hash and res0.top_block_hash == res2.top_block_hash:
|
|
break
|
|
time.sleep(10)
|
|
loops -= 1
|
|
assert loops >= 0
|
|
|
|
res = daemon.get_info()
|
|
cumulative_difficulty = res.cumulative_difficulty
|
|
|
|
# disconnect third daemon so it keeps the original chain
|
|
third_daemon.out_peers(0)
|
|
third_daemon.in_peers(0)
|
|
|
|
# mine
|
|
print('Mining on second daemon')
|
|
n_mined = 0
|
|
while True:
|
|
n_mined += 100
|
|
res = second_daemon.generateblocks('TF1MMEY5v2dN49XKNCKCdBqmTMM6GdZZA5UBbDgTewaUd3c2jDazN5yKrG1BBHX3UyPqKD9hrh3DpPTDmWiCmsuRpePT1MTaPxm', 1)
|
|
res = second_daemon.get_info()
|
|
if res.cumulative_difficulty > cumulative_difficulty:
|
|
break
|
|
print('Mined %u blocks for a reorg' % n_mined)
|
|
|
|
# reconnect daemons 1 and 2
|
|
daemon.out_peers(8)
|
|
daemon.in_peers(8)
|
|
second_daemon.out_peers(8)
|
|
second_daemon.in_peers(8)
|
|
|
|
# wait while the reorg happens
|
|
print('Waiting for reorg on first daemon')
|
|
while True:
|
|
res = daemon.get_info()
|
|
if res.cumulative_difficulty > cumulative_difficulty:
|
|
break
|
|
time.sleep(10)
|
|
|
|
# disconnect daemons again
|
|
daemon.out_peers(0)
|
|
daemon.in_peers(0)
|
|
second_daemon.out_peers(0)
|
|
second_daemon.in_peers(0)
|
|
|
|
# mine on the third daemon, which still has the original chain
|
|
res = third_daemon.generateblocks('TF1MMEY5v2dN49XKNCKCdBqmTMM6GdZZA5UBbDgTewaUd3c2jDazN5yKrG1BBHX3UyPqKD9hrh3DpPTDmWiCmsuRpePT1MTaPxm', n_mined + 1)
|
|
res = third_daemon.get_info()
|
|
cumulative_difficulty = res.cumulative_difficulty
|
|
|
|
# reconnect all daemons
|
|
daemon.out_peers(8)
|
|
daemon.in_peers(8)
|
|
second_daemon.out_peers(8)
|
|
second_daemon.in_peers(8)
|
|
third_daemon.out_peers(8)
|
|
third_daemon.in_peers(8)
|
|
|
|
# wait while the reorg happens
|
|
print('Waiting for reorg on first daemon')
|
|
while True:
|
|
res = daemon.get_info()
|
|
if res.cumulative_difficulty == cumulative_difficulty:
|
|
break
|
|
time.sleep(10)
|
|
|
|
print('Back on the original chain')
|
|
|
|
# disconnect all daemons
|
|
daemon.out_peers(0)
|
|
daemon.in_peers(0)
|
|
second_daemon.out_peers(0)
|
|
second_daemon.in_peers(0)
|
|
third_daemon.out_peers(0)
|
|
third_daemon.in_peers(0)
|
|
|
|
state1 = self.get_state()
|
|
assert self.remove_height(state0) == self.remove_height(state1), self.get_diff(state0, state1)
|
|
|
|
class Guard:
|
|
def __enter__(self):
|
|
for i in [2, 3, 4]:
|
|
Daemon(idx = i).out_peers(0)
|
|
Daemon(idx = i).in_peers(0)
|
|
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')
|
|
|
|
if __name__ == '__main__':
|
|
with Guard() as guard:
|
|
CCTest().run_test()
|