townforge/tests/functional_tests/cc.py

2673 lines
119 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
"""Test CC RPC
"""
from framework.daemon import Daemon
from framework.wallet import Wallet
FIRST_CITY_X = 466920160
FIRST_CITY_Y = 2502907875
ITEM_STONE = 1
ITEM_MEDIUM_STONE = 2
ITEM_WOOD = 4
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_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 = 20000
STONE_LAST_RESORT_PRICE = 300000
NEW_ITEM_FEE = 100000000
DISCOVERY_BUCKET_BRIGADE = 32
def RESOURCE_AVAILABILITY_SCALE(x):
return int((x) * 4)
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.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_giving()
self.test_discoveries()
self.test_game_update()
self.test_revert()
self.test_distance_from_generator()
self.test_custom_items()
self.test_badges()
self.test_resize_flag()
self.test_attributes()
self.test_hunt()
self.test_invitation()
self.reset_and_check_states()
state1 = self.get_state()
assert state0 == state1, self.get_diff(state0, state1)
def reset(self):
print('Resetting blockchain')
daemon = Daemon()
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 = 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 = 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
def mine(self):
print("Mining many blocks")
daemon = 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 test_cc_account_creation(self):
daemon = 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 = Daemon()
print("Testing CC account deposits/withdrawals")
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
def test_buy_land(self):
daemon = Daemon()
print("Testing buying land")
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
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 = Daemon()
print("Testing buying items")
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
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
def test_build(self):
daemon = 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]
def test_trading(self):
daemon = Daemon()
print("Testing trading")
res = daemon.get_height()
base_height = res.height
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]
def test_interacting_trades(self):
daemon = Daemon()
print("Testing interacting trades")
res = daemon.get_height()
base_height = res.height
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()
def test_giving(self):
daemon = Daemon()
print("Testing giving")
res = daemon.get_height()
base_height = res.height
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)
# 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]
def test_accrual_trades(self):
daemon = Daemon()
print("Testing accrual trades")
res = daemon.get_height()
base_height = res.height
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)
# 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
# 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)
# 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
# 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)
# 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)
daemon.flush_txpool()
def test_trade_third_party_matching(self):
daemon = Daemon()
print("Testing trade third party matching")
res = daemon.get_height()
base_height = res.height
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
# 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
daemon.flush_txpool()
def test_game_update(self):
daemon = 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 = 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
for i in range(16):
try:
res = daemon.cc_get_account(i)
state['account_' + str(i)] = res
except:
pass
for i in range(16):
try:
res = daemon.cc_get_flag(i)
state['flag_' + str(i)] = res
except:
pass
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
return state
def remove_height(self, state):
new_state = state.copy()
del new_state['info.height']
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 state1 == state3, self.get_diff(state1, state3)
self.wallet[3].refresh()
def test_revert(self):
daemon = 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", "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_distance_from_generator(self):
daemon = Daemon()
print("Testing building at a distance from generator")
res = self.wallet[2].refresh()
res = self.wallet[2].cc_get_info()
cc_balance = res.cc_balance
account_id = res.account_id
self.wallet[2].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 8*(650+2700 + 670 + 5000)}, {'type': ITEM_WOOD, 'amount': 8*(1200+2700 + 1800 + 3500)}, {'type': ITEM_LABOUR, 'amount': 8*(41000+123260 + 17200)}])
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
ox = FIRST_CITY_X + ORIGIN_RESOURCE_RADIUS
oy = FIRST_CITY_Y
# build a agricultural building to power the sawmill
res = daemon.cc_get_new_flag_cost(ox, oy, ox + 64 - 1, oy + 64 - 1)
cost = res.cost
res = self.wallet[2].cc_buy_land(ox, oy, ox + 64 - 1, oy + 64 - 1)
assert len(res.tx_hash) == 64
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
res = self.wallet[2].refresh()
res = daemon.cc_get_account(account_id)
assert len(res.flags) > 0
flag_id = res.flags[-1]
assert flag_id > 0
res = self.wallet[2].cc_building_settings(flag_id, ROLE_RESIDENTIAL1, 100)
assert len(res.tx_hash) == 64
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
res = daemon.cc_get_flag(flag_id, get_tiles = False)
assert res.role == ROLE_RESIDENTIAL1
# build a sawmill
res = daemon.cc_get_new_flag_cost(ox, oy + 64, ox + 60 - 1, oy + 64 + 60 - 1)
cost = res.cost
res = self.wallet[2].cc_buy_land(ox, oy + 64, ox + 60 - 1, oy + 64 + 60 - 1)
assert len(res.tx_hash) == 64
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
res = self.wallet[2].refresh()
res = daemon.cc_get_account(account_id)
assert len(res.flags) > 0
flag_id_sawmill = res.flags[-1]
assert flag_id_sawmill > 0
res = self.wallet[2].cc_building_settings(flag_id_sawmill, ROLE_SAWMILL, 100)
assert len(res.tx_hash) == 64
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
res = self.wallet[2].cc_build(flag_id_sawmill, 0, 0, 3, 3, block_data = [128 | 8 , ITEM_STONE], build_height = 0, encoded = True)
res = self.wallet[2].cc_build(flag_id_sawmill, 0, 0, 3, 3, block_data = [128 | 8 , ITEM_WOOD], build_height = 1, encoded = True, parent = res.cc_nonce)
res = self.wallet[2].cc_build(flag_id_sawmill, 0, 0, 3, 3, block_data = [128 | 8 , ITEM_WOOD], build_height = 2, encoded = True, parent = res.cc_nonce)
res = self.wallet[2].cc_build(flag_id_sawmill, 0, 0, 3, 3, block_data = [128 | 8 , ITEM_WOOD], build_height = 3, encoded = True, parent = res.cc_nonce)
res = self.wallet[2].cc_build(flag_id_sawmill, 0, 0, 3, 3, block_data = [128 | 8 , ITEM_WOOD], build_height = 4, encoded = True, parent = res.cc_nonce)
res = self.wallet[2].cc_build(flag_id_sawmill, 0, 0, 3, 3, block_data = [128 | 8 , ITEM_WOOD], build_height = 5, encoded = True, parent = res.cc_nonce)
res = self.wallet[2].cc_build(flag_id_sawmill, 0, 0, 3, 3, block_data = [128 | 8 , ITEM_WOOD], build_height = 6, encoded = True, parent = res.cc_nonce)
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 7)
# build a stonecutter
res = daemon.cc_get_new_flag_cost(ox, oy + 128, ox + 60 - 1, oy + 128 + 60 - 1)
cost = res.cost
res = self.wallet[2].cc_buy_land(ox, oy + 128, ox + 60 - 1, oy + 128 + 60 - 1)
assert len(res.tx_hash) == 64
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
res = self.wallet[2].refresh()
res = daemon.cc_get_account(account_id)
assert len(res.flags) > 0
flag_id_stonecutter = res.flags[-1]
assert flag_id_stonecutter > 0
res = self.wallet[2].cc_building_settings(flag_id_stonecutter, ROLE_STONECUTTER, 100)
assert len(res.tx_hash) == 64
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
res = self.wallet[2].cc_build(flag_id_stonecutter, 0, 0, 3, 3, block_data = [128 | 8 , ITEM_STONE], build_height = 0, encoded = True)
res = self.wallet[2].cc_build(flag_id_stonecutter, 0, 0, 3, 3, block_data = [128 | 8 , ITEM_WOOD], build_height = 1, encoded = True, parent = res.cc_nonce)
res = self.wallet[2].cc_build(flag_id_stonecutter, 0, 0, 3, 3, block_data = [128 | 8 , ITEM_WOOD], build_height = 2, encoded = True, parent = res.cc_nonce)
res = self.wallet[2].cc_build(flag_id_stonecutter, 0, 0, 3, 3, block_data = [128 | 8 , ITEM_WOOD], build_height = 3, encoded = True, parent = res.cc_nonce)
res = self.wallet[2].cc_build(flag_id_stonecutter, 0, 0, 3, 3, block_data = [128 | 8 , ITEM_WOOD], build_height = 4, encoded = True, parent = res.cc_nonce)
res = self.wallet[2].cc_build(flag_id_stonecutter, 0, 0, 3, 3, block_data = [128 | 8 , ITEM_WOOD], build_height = 5, encoded = True, parent = res.cc_nonce)
res = self.wallet[2].cc_build(flag_id_stonecutter, 0, 0, 3, 3, block_data = [128 | 8 , ITEM_WOOD], build_height = 6, encoded = True, parent = res.cc_nonce)
res = self.wallet[2].cc_build(flag_id_stonecutter, 0, 0, 3, 3, block_data = [128 | 8 , ITEM_WOOD], build_height = 7, encoded = True, parent = res.cc_nonce)
res = self.wallet[2].cc_build(flag_id_stonecutter, 0, 0, 3, 3, block_data = [128 | 8 , ITEM_WOOD], build_height = 8, encoded = True, parent = res.cc_nonce)
res = self.wallet[2].cc_build(flag_id_stonecutter, 0, 0, 3, 3, block_data = [128 | 8 , ITEM_WOOD], build_height = 9, encoded = True, parent = res.cc_nonce)
res = self.wallet[2].cc_build(flag_id_stonecutter, 0, 0, 3, 3, block_data = [128 | 8 , ITEM_WOOD], build_height = 10, encoded = True, parent = res.cc_nonce)
res = self.wallet[2].cc_build(flag_id_stonecutter, 0, 0, 3, 3, block_data = [128 | 8 , ITEM_WOOD], build_height = 11, encoded = True, parent = res.cc_nonce)
res = self.wallet[2].cc_build(flag_id_stonecutter, 0, 0, 3, 3, block_data = [128 | 8 , ITEM_WOOD], build_height = 12, encoded = True, parent = res.cc_nonce)
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 13)
# mine enough to pass one update
res = daemon.get_info()
height = res.height
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
res = daemon.cc_get_last_update_events()
res = daemon.cc_get_flag(flag_id_sawmill, get_tiles = False)
assert res.role == ROLE_SAWMILL
assert res.active
sawmill_influence = res.influence
sawmill_availability = RESOURCE_AVAILABILITY_SCALE(sawmill_influence)
sawmill_x0 = res.x0
sawmill_y0 = res.y0
sawmill_x1 = res.x1
sawmill_y1 = res.y1
res = daemon.cc_get_flag(flag_id_stonecutter, get_tiles = False)
assert res.role == ROLE_STONECUTTER
assert res.active
stonecutter_influence = res.influence
stonecutter_availability = RESOURCE_AVAILABILITY_SCALE(stonecutter_influence)
stonecutter_x0 = res.x0
stonecutter_y0 = res.y0
stonecutter_x1 = res.x1
stonecutter_y1 = res.y1
previous_budget = None
original_labour = None
original_wood = None
original_stone = None
for distance in [-10, 1, 1 + sawmill_availability, 8 + sawmill_availability * 5 / 2, 8 + sawmill_availability * 7 / 2]:
x = FIRST_CITY_X + 4 + ORIGIN_RESOURCE_RADIUS + distance
y = FIRST_CITY_Y + 4 - 160
res = daemon.cc_get_new_flag_cost(x, y, x + 5 - 1, y + 5 - 1)
cost = res.cost
res = self.wallet[2].cc_buy_land(x, y, x + 5 - 1, y + 5 - 1)
assert len(res.tx_hash) == 64
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
res = self.wallet[2].refresh()
res = daemon.cc_get_account(account_id)
assert len(res.flags) > 0
flag_id = res.flags[-1]
assert flag_id > 0
res = self.wallet[2].cc_building_settings(flag_id, ROLE_RESIDENTIAL1, 100, [flag_id_sawmill, flag_id_stonecutter])
assert len(res.tx_hash) == 64
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
res = daemon.cc_get_flag(flag_id, get_tiles = False)
x0 = res.x0
y0 = res.y0
x1 = res.x1
y1 = res.y1
budget = res.budget
if previous_budget:
previous_budget_without_labour = [x for x in previous_budget if x['type'] != ITEM_LABOUR]
budget_without_labour = [x for x in budget if x['type'] != ITEM_LABOUR]
assert previous_budget_without_labour == budget_without_labour
labour = [x['amount'] for x in budget if x['type'] == ITEM_LABOUR][0]
previous_labour = [x['amount'] for x in previous_budget if x['type'] == ITEM_LABOUR][0]
assert labour >= previous_labour
sawmill_distance = get_distance(x0, y0, x1, y1, sawmill_x0, sawmill_y0, sawmill_x1, sawmill_y1)
stonecutter_distance = get_distance(x0, y0, x1, y1, stonecutter_x0, stonecutter_y0, stonecutter_x1, stonecutter_y1)
expected_labour = original_labour
expected_labour += int((max(sawmill_distance / float(sawmill_availability) - 1, 0)) * original_wood)
expected_labour += int((max(stonecutter_distance / float(stonecutter_availability) - 1, 0)) * original_stone)
assert(abs(labour / float(expected_labour) - 1.0) <= 0.02) # 2% leeway
else:
original_labour = [x['amount'] for x in budget if x['type'] == ITEM_LABOUR][0]
original_wood = [x['amount'] for x in budget if x['type'] == ITEM_WOOD][0]
original_stone = [x['amount'] for x in budget if x['type'] == ITEM_STONE][0]
previous_budget = budget
print('Testing building beyond the generator max limit')
distance = sawmill_availability * MAX_DISTANCE_PERCENTAGE / 100
x = FIRST_CITY_X + 4 + ORIGIN_RESOURCE_RADIUS + distance + 8
y = FIRST_CITY_Y + 4 + 160
res = daemon.cc_get_new_flag_cost(x, y, x + 5 - 1, y + 5 - 1)
cost = res.cost
res = self.wallet[2].cc_buy_land(x, y, x + 5 - 1, y + 5 - 1)
assert len(res.tx_hash) == 64
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
res = self.wallet[2].refresh()
res = daemon.cc_get_account(account_id)
assert len(res.flags) > 0
flag_id = res.flags[-1]
assert flag_id > 0
ok = False
try: self.wallet[2].cc_building_settings(flag_id, ROLE_STONECUTTER, 100, [flag_id_sawmill, flag_id_stonecutter])
except: ok = True
assert ok
def test_custom_items(self):
daemon = Daemon()
print("Testing custom items")
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", "primary desc", "secondary desc")
except: ok = True
assert ok
ok = False
try: self.wallet[2].cc_new_item(100, "", "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", "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"
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", "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"
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]
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]
# 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)
# 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]
def test_badges(self):
daemon = Daemon()
print("Testing badges")
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
def test_resize_flag(self):
daemon = Daemon()
print("Testing resizing flags")
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 = 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 = 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 = 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)
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
def test_invitation(self):
daemon = 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
# 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_discoveries(self):
daemon = 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 * 10
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
if __name__ == '__main__':
CCTest().run_test()