mirror of
https://github.com/Chia-Network/chia-blockchain.git
synced 2024-09-20 16:08:51 +03:00
7e3e18bdfd
* Resend transactions (#11167) * Resend transactions * Don't recheck transactions more frequently than timeout * Add wallet resend parameter to config, move timeout code out of tx store, but close to call site * Add a test for wallet transaction resend * Add test for wallet retry * isort new files for precommit and update workflows * Use correct fixture name * LGTM - remove unused import Co-authored-by: Earle Lowe <e.lowe@chia.net> * less except -> false (#10219) * less except -> false * establish_connection() and .perform_handshake() can just return None * remove more pointless, and no wrong, assertions * Write python version error to stderr (#11239) Co-authored-by: wjblanke <wjb98672@gmail.com> * simplify SizedBytes and StructStream (#11429) * simplify SizedBytes and StructStream * lint * super() !!! * do not pass parameter up to super().__init__() * Update chia/util/struct_stream.py Co-authored-by: Arvid Norberg <arvid@libtorrent.org> * parse fixed-width int data from class name * add int512 and uint128 .from_bytes(), test .parse() failures * test serialization against struct.pack() * use typing_extensions for final * override ignore * stop using struct for StructStream oh the irony * fixup .to_bytes() to accept parameters again for where we use that * bring back signed parameter * format * adjust tests for new exception * eliminate custom coding for uint128 and int512 * tidy * remove unused StructStream.PACK attribute * add direct tests for parse_metadata_from_name() * stricter hinting * remove no-longer-needed typeshed work-around * apply strict type checking to all touched files * remove StructStream override of .to_bytes() * tidy * types touchup * add unused parameter comments Co-authored-by: Arvid Norberg <arvid@libtorrent.org> Co-authored-by: wjblanke <wjb98672@gmail.com> * Allow services to set a non-default max request body size limit (#11516) * updated bls to 13 (#11529) * reduce the redundant computations of coin_ids in block_body_validation (#11530) * add test for streamable -> json conversion (#11527) * add test for streamable -> json conversion * fixup test * Uses the new `from_bytes_unchecked` method in blspy, to improve perfo… (#11463) * Uses the new `from_bytes_unchecked` method in blspy, to improve performance * Update test * Fix merge conflict * Use from_bytes_unchecked in post_init and from_json * More uniform code * rename test files that are missing test_ prefix (#10712) * rename test files that are missing test_ prefix * update mypy and isort excludes * skip test_get_host_addr6() in GitHub Actions under macOS * rebuild workflows * Coin Selection Refactor With CAT Coin Selection Refactor (#9975) * add exact match and best exact match algorithms * optimize algorithm further this might be good. * lint * fix bad logic * add final algorithms * delete lint * oops * Update coin_selection.py * simplify and fix knapsack algoritm * simplify code and correct logic * make it way better. * clarify comments and check for edge cases. * add comments and stuff * improve coin selection addressed comments Thanks! * add coin_selection rpc tests. * clean up and add new unit tests * undo test changes * add extra test cases * move coin_selection to its own function and switch to it for cat and main wallet. * add cat tests * lint * make function align with standards also removed test * make test better * add proper types * Improve code clarity * wallet: fix coin selection bugs * wallet: add an assert just in case * tests: add some sleeps to reduce flakiness * Isort Co-authored-by: Kyle Altendorf <sda@fstab.net> * fix bad merge * lint * fix tests * address aforementioned changes. * remove wallet test * isort * more tests and fixes * lint * rename to amount for coin selection rpc * fix incase we have no smaller coins * fix tests + lint * re add asserts * oops missed me. * lint * fix test * Squashed commit of the following: commit34a2235de5
Author: Jack Nelson <jack@jacknelson.xyz> Date: Wed Apr 13 10:09:42 2022 -0400 clarify comment commitadbf7f4f94
Author: Jack Nelson <jack@jacknelson.xyz> Date: Tue Apr 12 20:27:05 2022 -0400 linty lint commit5ebc1ac9fd
Author: Jack Nelson <jack@jacknelson.xyz> Date: Tue Apr 12 20:17:19 2022 -0400 add failure test and final changes commit7e5a21b4c2
Author: Jack Nelson <jack@jacknelson.xyz> Date: Tue Apr 12 19:35:18 2022 -0400 add descriptions and slim down code commit31c95b916d
Merge:d7b91295b
d9b0ef5f3
Author: Jack Nelson <jack@jacknelson.xyz> Date: Mon Apr 11 10:12:05 2022 -0400 Merge branch 'jack-cat-coinselection' into jn_coinselection_dust commitd7b91295b5
Author: Jack Nelson <jack@jacknelson.xyz> Date: Sun Apr 10 20:31:09 2022 -0400 lint commit30dc7c0ab4
Author: Jack Nelson <jack@jacknelson.xyz> Date: Sun Apr 10 20:25:52 2022 -0400 fix tests commit6c8c2e4874
Author: Jack Nelson <jack@jacknelson.xyz> Date: Thu Mar 31 15:06:00 2022 -0400 remove duplicate code. commit9f79b6f304
Author: Jack Nelson <jack@jacknelson.xyz> Date: Thu Mar 31 15:01:10 2022 -0400 address more concerns commit67c1b3929f
Author: Jack Nelson <jack@jacknelson.xyz> Date: Thu Mar 31 12:59:05 2022 -0400 fix logic error commit2d19a53245
Author: Jack Nelson <jack@jacknelson.xyz> Date: Thu Mar 31 11:47:52 2022 -0400 simplify and de duplicate code commit6ab1cc79bb
Author: Jack Nelson <jack@jacknelson.xyz> Date: Wed Mar 30 21:34:50 2022 -0400 add function and select individual coin commit582c17aa8d
Merge:ce2165942
618fbaeba
Author: Jack Nelson <jack@jacknelson.xyz> Date: Wed Mar 30 21:14:37 2022 -0400 Merge branch 'jack-cat-coinselection' into jn_coinselection_dust commitce21659429
Merge:16aabb3fd
6daba28db
Author: Jack Nelson <jack@jacknelson.xyz> Date: Wed Mar 30 20:53:21 2022 -0400 Merge branch 'jack-cat-coinselection' into jn_coinselection_dust commit16aabb3fd5
Merge:0b9fc2845
2286fe426
Author: Jack Nelson <jack@jacknelson.xyz> Date: Wed Mar 30 20:49:02 2022 -0400 Merge branch 'jack-cat-coinselection' into jn_coinselection_dust commit0b9fc28455
Author: Jack Nelson <jack@jacknelson.xyz> Date: Wed Mar 30 20:38:12 2022 -0400 lint commit62e74c72f4
Author: Jack Nelson <jack@jacknelson.xyz> Date: Wed Mar 30 20:34:22 2022 -0400 fix logic and tests commite738f44320
Author: Jack Nelson <jack@jacknelson.xyz> Date: Wed Mar 30 18:52:05 2022 -0400 deal with dust and add tests * make sure that we do not use any dust * minor change * address concerns * adjust comments * adjust comment Co-authored-by: Mariano Sorgente <sorgente711@gmail.com> Co-authored-by: Kyle Altendorf <sda@fstab.net> * rebuild workflows (#11543) * remove the cache from CoinStore. It appears the cost of maintaining the cache outweighs the gains. (#11540) * Keep daemon websocket alive during keyring unlock (#11371) * When prompting to unlock the keyring during daemon launch, it's possible that the daemon websocket connection will timeout before the user has entered their passphrase. We can't quickly detect that the connection has timed-out, so instead we now reconnect after collecting the passphrase, unlock the keyring, and then close the old connection. * mypy fix * Switch to using asyncio.loop.run_in_executor to collect the passphrase on its own thread. * Use a new ThreadPoolExecutor configured with 1 worker thread. * Support searching derived addresses on testnet. (#11449) * Support searching derived addresses on testnet. * Added tests * Optimize code to not perform useless subgroup checks (#11546) * Optimize code to not perform useless subgroup checks * Revert less important optimizations * hints and strict type checking for test_wallet (#11541) * hints and strict type checking for test_wallet * fixup * flip flop * disable pytest-monitor by default (#11507) * disable pytest-monitor by default * take 2 * make recurse_jsonify() work directly on types (#11537) * make recurse_jsonify() work directly on types, circumventing the dataclasses.asdict() step. This enables simpler integration of non dataclasses into the Streamable and JSON protocols * add benchmark for Streamable.to_json_dict() * tests: Split up and improve `test_wallet_rpc.py` (#11552) This breaks up the one big test into ``` test_send_transaction test_create_signed_transaction test_create_signed_transaction_with_coin_announcement test_create_signed_transaction_with_puzzle_announcement test_send_transaction_multi test_get_transactions test_get_transaction_count test_cat_endpoints test_offer_endpoints test_key_and_address_endpoints ``` Note that there is still much more room for improvements. Also the following tests can still be split up more: ``` test_get_transactions test_cat_endpoints test_offer_endpoints test_key_and_address_endpoints ``` * Remove unneeded uint64() intermediate in CAT wallet (#11575) * Get get_args() and get_origin() from typing_extensions (#11571) * Get get_args() and get_origin() from typing_extensions * Update streamable.py * cleanup * Fix several flaky tests (#11576) * Increase some of the timeouts to reduce flakiness * Experiment with CI for flakiness * Force more runs * Add argument name * Fix flaky mempool test * Attempt to fix another flaky test * Fix wallet retry test * Missing arg * Lint * Increase benchmark test time * Debug * Debug * Simplify retry test * Lint * More lint * Return false instead of assert * No need to check disconnect twice (since we don't break, this was flaky) * Remove useless changes * Accidental changes revert * Accidental changes revert 2 * Accidental changes revert 3 * Revert fixture * Fix a few additional flaky tests (#11597) * Fix a few additional flaky tests * Lint * Update tests/core/full_node/stores/test_full_node_store.py Co-authored-by: Jeff <jeff@chia.net> * Fix merge conflict * Remove unnecessary function Co-authored-by: Jeff <jeff@chia.net> * Bind port 0 to fix race condition when grabbing available ports (#11578) * port 0 to fix flakiness * Try fixing setup_full_system * Try fixing setup_full_system, and lint * More attempts to fix * No more calls to get random ports in setup_nodes * Revert accidental changes * Timelord extra arg * Try with port 0 * Fix daemon test, and lint * Try without 0.0.0.0 * Back to 0.0.0.0 * Try a few timelord changes to get test running * Increase timeout again * Use the correct interface to get the port * INFO logging to debug issue * Revert "INFO logging to debug issue" This reverts commit7c379e5cca
. * Fix advertised port log * Add extra log * Logging back * Rollback the timelord changes * Try port 0 timelord * Revert "Try port 0 timelord" This reverts commit4997faf3b2
. * Try full green, change ordering * Remove unused var * speed up simulation and cleanup * Now try without the port config * Fix a flaky call to get_event_loop * Try getting the port dynamically * No dynamic port * Try changing the ordering * Try adding a sleep * Back to what works * Timelord before vdf clients * Dynamic port for 1st timelord * Revert "Dynamic port for 1st timelord" This reverts commit0f322a15b7
. * Revert "Timelord before vdf clients" This reverts commit3286c34696
. * Revert "Back to what works" This reverts commit30380dffb7
. * Revert "Try adding a sleep" This reverts commit9212b665a6
. * Revert "Try changing the ordering" This reverts commita62597d70d
. * Revert "No dynamic port" This reverts commit5d2e15749b
. * Revert "Try getting the port dynamically" This reverts commitef9cd75679
. * Revert "Fix a flaky call to get_event_loop" This reverts commit01a000fdfb
. * Try one to 0 * Just not 0 * Don't get port dynamically * Cleanup a bit * Fix * Some cleanup work * Some cleanup work * Fix daemon test * Cleanup * Remove arguments * restore missing hints being stored as None (instead of 0-length bytes) (#11568) * Coin simplification (#11567) * factor out as_list() from Coin into free function. Remove unused name_str() from Coin. Minor optimization of hash_coin_ids() for common case. * extend Coin unit test * test installer on fedora:36, drop 33 * add tests.util.misc.assert_maximum_duration for benchmark assertions (#11589) * add tests.util.misc.assert_maximum_duration for benchmark assertions * fix some imports * more * lint * correct duration * hint fixup * rename to caller_file_and_line() * set default timer to thread_time() * extract gc manager and default to disabling * self calibrate overhead * wrap none-ness behind .results() method * add messages * from __future__ import annotations * yield out self * final from typing_extensions * split it * just use Future * tweak * tweak * correction in loosely hint checked file * all future indexing in hints * union for the hints * rename * assert_runtime() * another rename... * message -> label * label all results with test names * oops * early return from _set_spent function (#11594) * check for removals before calling function * move condition to function * remove redundant condition (#11582) * fix built-in profiler to work for mac (#11590) * Bump actions/setup-python from 2 to 3 (#10949) * Bump actions/setup-python from 2 to 3 Bumps [actions/setup-python](https://github.com/actions/setup-python) from 2 to 3. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> * Fixup templates for python@v3 Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Gene Hoffman <hoffmang@hoffmang.com> * avoid cancelling release/** and long_lived/** (#11519) * tests: Some adjustments in `test_offer_endpoints` (#11558) This is a follow up after #11552 which basically used the initial parts of `test_cat_endpoints` to make `test_offer_endpoints` working. Now this PR drops a lot of the stuff we can assume to be not needed in this test because its tested in `test_cat_endpoints` and it adds some general improvments to it. * async sleep and require connection reset error for DoS test (#11612) * fix jsonify bool * Remove is not None and length assertion in select_coins() (#11569) * Remove is not None and length assertion in select_coins() The `coins is not None` check seems unneeded since `select_coins()` is hinted to return `Set[Coin]`. The length requirement needlessly restricts from being able to request a zero amount. Either situation would either trigger an exception in the next assert, or trigger the assert itself for non-zero amounts requested. * also remove from cat_wallet.py * new port 0 stuff Co-authored-by: Adam Kelly <338792+aqk@users.noreply.github.com> Co-authored-by: Earle Lowe <e.lowe@chia.net> Co-authored-by: Evan Graham <me@luakt.net> Co-authored-by: wjblanke <wjb98672@gmail.com> Co-authored-by: Arvid Norberg <arvid@libtorrent.org> Co-authored-by: Mariano Sorgente <3069354+mariano54@users.noreply.github.com> Co-authored-by: Jack Nelson <jack@jacknelson.xyz> Co-authored-by: Mariano Sorgente <sorgente711@gmail.com> Co-authored-by: Jeff <jeff@chia.net> Co-authored-by: dustinface <35775977+xdustinface@users.noreply.github.com> Co-authored-by: neurosis69 <83925572+neurosis69@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Gene Hoffman <hoffmang@hoffmang.com> Co-authored-by: William Allen <wallentx@users.noreply.github.com>
913 lines
37 KiB
Python
913 lines
37 KiB
Python
import asyncio
|
|
import time
|
|
from typing import List, Tuple
|
|
|
|
import pytest
|
|
|
|
from chia.consensus.block_rewards import calculate_base_farmer_reward, calculate_pool_reward
|
|
from chia.protocols.full_node_protocol import RespondBlock
|
|
from chia.server.server import ChiaServer
|
|
from chia.simulator.full_node_simulator import FullNodeSimulator
|
|
from chia.simulator.simulator_protocol import FarmNewBlockProtocol, ReorgProtocol
|
|
from chia.types.blockchain_format.program import Program
|
|
from chia.types.blockchain_format.sized_bytes import bytes32
|
|
from chia.types.peer_info import PeerInfo
|
|
from chia.util.ints import uint16, uint32, uint64
|
|
from chia.wallet.derive_keys import master_sk_to_wallet_sk
|
|
from chia.wallet.transaction_record import TransactionRecord
|
|
from chia.wallet.util.compute_memos import compute_memos
|
|
from chia.wallet.util.transaction_type import TransactionType
|
|
from chia.wallet.util.wallet_types import AmountWithPuzzlehash
|
|
from chia.wallet.wallet_node import WalletNode
|
|
from chia.wallet.wallet_state_manager import WalletStateManager
|
|
from tests.pools.test_pool_rpc import wallet_is_synced
|
|
from tests.time_out_assert import time_out_assert, time_out_assert_not_none
|
|
from tests.wallet.cat_wallet.test_cat_wallet import tx_in_pool
|
|
|
|
|
|
class TestWalletSimulator:
|
|
@pytest.mark.parametrize(
|
|
"trusted",
|
|
[True, False],
|
|
)
|
|
@pytest.mark.asyncio
|
|
async def test_wallet_coinbase(
|
|
self,
|
|
wallet_node_sim_and_wallet: Tuple[List[FullNodeSimulator], List[Tuple[WalletNode, ChiaServer]]],
|
|
trusted: bool,
|
|
self_hostname: str,
|
|
) -> None:
|
|
num_blocks = 10
|
|
full_nodes, wallets = wallet_node_sim_and_wallet
|
|
full_node_api = full_nodes[0]
|
|
server_1: ChiaServer = full_node_api.full_node.server
|
|
wallet_node, server_2 = wallets[0]
|
|
|
|
assert wallet_node.wallet_state_manager is not None
|
|
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
ph = await wallet.get_new_puzzlehash()
|
|
if trusted:
|
|
wallet_node.config["trusted_peers"] = {server_1.node_id.hex(): server_1.node_id.hex()}
|
|
else:
|
|
wallet_node.config["trusted_peers"] = {}
|
|
|
|
await server_2.start_client(PeerInfo(self_hostname, uint16(server_1._port)), None)
|
|
for i in range(0, num_blocks):
|
|
await full_node_api.farm_new_block(FarmNewBlockProtocol(ph))
|
|
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
|
|
funds = sum(
|
|
[
|
|
calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i))
|
|
for i in range(1, num_blocks + 2)
|
|
]
|
|
)
|
|
|
|
async def check_tx_are_pool_farm_rewards() -> bool:
|
|
assert wallet_node.wallet_state_manager is not None
|
|
wsm: WalletStateManager = wallet_node.wallet_state_manager
|
|
all_txs = await wsm.get_all_transactions(1)
|
|
expected_count = (num_blocks + 1) * 2
|
|
if len(all_txs) != expected_count:
|
|
return False
|
|
pool_rewards = 0
|
|
farm_rewards = 0
|
|
|
|
for tx in all_txs:
|
|
if TransactionType(tx.type) == TransactionType.COINBASE_REWARD:
|
|
pool_rewards += 1
|
|
elif TransactionType(tx.type) == TransactionType.FEE_REWARD:
|
|
farm_rewards += 1
|
|
|
|
if pool_rewards != expected_count / 2:
|
|
return False
|
|
if farm_rewards != expected_count / 2:
|
|
return False
|
|
return True
|
|
|
|
await time_out_assert(10, check_tx_are_pool_farm_rewards, True)
|
|
await time_out_assert(5, wallet.get_confirmed_balance, funds)
|
|
|
|
@pytest.mark.parametrize(
|
|
"trusted",
|
|
[True, False],
|
|
)
|
|
@pytest.mark.asyncio
|
|
async def test_wallet_make_transaction(
|
|
self,
|
|
two_wallet_nodes: Tuple[List[FullNodeSimulator], List[Tuple[WalletNode, ChiaServer]]],
|
|
trusted: bool,
|
|
self_hostname: str,
|
|
) -> None:
|
|
num_blocks = 5
|
|
full_nodes, wallets = two_wallet_nodes
|
|
full_node_api = full_nodes[0]
|
|
server_1 = full_node_api.full_node.server
|
|
wallet_node, server_2 = wallets[0]
|
|
assert wallet_node.wallet_state_manager is not None
|
|
wallet_node_2, server_3 = wallets[1]
|
|
assert wallet_node_2.wallet_state_manager is not None
|
|
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
ph = await wallet.get_new_puzzlehash()
|
|
if trusted:
|
|
wallet_node.config["trusted_peers"] = {server_1.node_id.hex(): server_1.node_id.hex()}
|
|
wallet_node_2.config["trusted_peers"] = {server_1.node_id.hex(): server_1.node_id.hex()}
|
|
else:
|
|
wallet_node.config["trusted_peers"] = {}
|
|
wallet_node_2.config["trusted_peers"] = {}
|
|
|
|
await server_2.start_client(PeerInfo(self_hostname, uint16(server_1._port)), None)
|
|
|
|
for i in range(0, num_blocks):
|
|
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
|
|
funds = sum(
|
|
[calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i)) for i in range(1, num_blocks)]
|
|
)
|
|
|
|
await time_out_assert(5, wallet.get_confirmed_balance, funds)
|
|
await time_out_assert(5, wallet.get_unconfirmed_balance, funds)
|
|
|
|
tx = await wallet.generate_signed_transaction(
|
|
uint64(10),
|
|
await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash(),
|
|
uint64(0),
|
|
)
|
|
await wallet.push_transaction(tx)
|
|
|
|
await time_out_assert(5, wallet.get_confirmed_balance, funds)
|
|
await time_out_assert(5, wallet.get_unconfirmed_balance, funds - 10)
|
|
await time_out_assert(5, full_node_api.full_node.mempool_manager.get_spendbundle, tx.spend_bundle, tx.name)
|
|
|
|
for i in range(0, num_blocks):
|
|
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
|
|
new_funds = sum(
|
|
[
|
|
calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i))
|
|
for i in range(1, (2 * num_blocks))
|
|
]
|
|
)
|
|
|
|
await time_out_assert(5, wallet.get_confirmed_balance, new_funds - 10)
|
|
await time_out_assert(5, wallet.get_unconfirmed_balance, new_funds - 10)
|
|
|
|
@pytest.mark.parametrize(
|
|
"trusted",
|
|
[True, False],
|
|
)
|
|
@pytest.mark.asyncio
|
|
async def test_wallet_coinbase_reorg(
|
|
self,
|
|
wallet_node_sim_and_wallet: Tuple[List[FullNodeSimulator], List[Tuple[WalletNode, ChiaServer]]],
|
|
trusted: bool,
|
|
self_hostname: str,
|
|
) -> None:
|
|
num_blocks = 5
|
|
full_nodes, wallets = wallet_node_sim_and_wallet
|
|
full_node_api = full_nodes[0]
|
|
fn_server = full_node_api.full_node.server
|
|
wallet_node, server_2 = wallets[0]
|
|
assert wallet_node.wallet_state_manager is not None
|
|
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
ph = await wallet.get_new_puzzlehash()
|
|
if trusted:
|
|
wallet_node.config["trusted_peers"] = {fn_server.node_id.hex(): fn_server.node_id.hex()}
|
|
else:
|
|
wallet_node.config["trusted_peers"] = {}
|
|
await server_2.start_client(PeerInfo(self_hostname, uint16(fn_server._port)), None)
|
|
await asyncio.sleep(5)
|
|
for i in range(0, num_blocks):
|
|
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
|
|
funds = sum(
|
|
[calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i)) for i in range(1, num_blocks)]
|
|
)
|
|
|
|
await time_out_assert(25, wallet.get_confirmed_balance, funds)
|
|
|
|
await full_node_api.reorg_from_index_to_new_index(
|
|
ReorgProtocol(uint32(2), uint32(num_blocks + 6), bytes32(32 * b"0"))
|
|
)
|
|
|
|
funds = sum(
|
|
[
|
|
calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i))
|
|
for i in range(1, num_blocks - 2)
|
|
]
|
|
)
|
|
|
|
await time_out_assert(5, wallet.get_confirmed_balance, funds)
|
|
|
|
@pytest.mark.parametrize(
|
|
"trusted",
|
|
[True, False],
|
|
)
|
|
@pytest.mark.asyncio
|
|
async def test_wallet_send_to_three_peers(
|
|
self,
|
|
three_sim_two_wallets: Tuple[List[FullNodeSimulator], List[Tuple[WalletNode, ChiaServer]]],
|
|
trusted: bool,
|
|
self_hostname: str,
|
|
) -> None:
|
|
num_blocks = 10
|
|
full_nodes, wallets = three_sim_two_wallets
|
|
|
|
wallet_0, wallet_server_0 = wallets[0]
|
|
assert wallet_0.wallet_state_manager is not None
|
|
|
|
full_node_api_0 = full_nodes[0]
|
|
full_node_api_1 = full_nodes[1]
|
|
full_node_api_2 = full_nodes[2]
|
|
|
|
full_node_0 = full_node_api_0.full_node
|
|
full_node_1 = full_node_api_1.full_node
|
|
full_node_2 = full_node_api_2.full_node
|
|
|
|
server_0 = full_node_0.server
|
|
server_1 = full_node_1.server
|
|
server_2 = full_node_2.server
|
|
|
|
ph = await wallet_0.wallet_state_manager.main_wallet.get_new_puzzlehash()
|
|
if trusted:
|
|
wallet_0.config["trusted_peers"] = {
|
|
server_0.node_id.hex(): server_0.node_id.hex(),
|
|
server_1.node_id.hex(): server_1.node_id.hex(),
|
|
server_2.node_id.hex(): server_2.node_id.hex(),
|
|
}
|
|
|
|
else:
|
|
wallet_0.config["trusted_peers"] = {}
|
|
|
|
# wallet0 <-> sever0
|
|
await wallet_server_0.start_client(PeerInfo(self_hostname, uint16(server_0._port)), None)
|
|
|
|
for i in range(0, num_blocks):
|
|
await full_node_api_0.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
|
|
all_blocks = await full_node_api_0.get_all_full_blocks()
|
|
|
|
for block in all_blocks:
|
|
await full_node_1.respond_block(RespondBlock(block))
|
|
await full_node_2.respond_block(RespondBlock(block))
|
|
|
|
funds = sum(
|
|
[calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i)) for i in range(1, num_blocks)]
|
|
)
|
|
|
|
await time_out_assert(5, wallet_0.wallet_state_manager.main_wallet.get_confirmed_balance, funds)
|
|
|
|
tx = await wallet_0.wallet_state_manager.main_wallet.generate_signed_transaction(
|
|
uint64(10), bytes32(32 * b"0"), uint64(0)
|
|
)
|
|
assert tx.spend_bundle is not None
|
|
await wallet_0.wallet_state_manager.main_wallet.push_transaction(tx)
|
|
|
|
await time_out_assert_not_none(5, full_node_0.mempool_manager.get_spendbundle, tx.spend_bundle.name())
|
|
|
|
# wallet0 <-> sever1
|
|
await wallet_server_0.start_client(PeerInfo(self_hostname, uint16(server_1._port)), wallet_0.on_connect)
|
|
|
|
await time_out_assert_not_none(15, full_node_1.mempool_manager.get_spendbundle, tx.spend_bundle.name())
|
|
|
|
# wallet0 <-> sever2
|
|
await wallet_server_0.start_client(PeerInfo(self_hostname, uint16(server_2._port)), wallet_0.on_connect)
|
|
|
|
await time_out_assert_not_none(15, full_node_2.mempool_manager.get_spendbundle, tx.spend_bundle.name())
|
|
|
|
@pytest.mark.parametrize(
|
|
"trusted",
|
|
[True, False],
|
|
)
|
|
@pytest.mark.asyncio
|
|
async def test_wallet_make_transaction_hop(
|
|
self,
|
|
two_wallet_nodes_five_freeze: Tuple[List[FullNodeSimulator], List[Tuple[WalletNode, ChiaServer]]],
|
|
trusted: bool,
|
|
self_hostname: str,
|
|
) -> None:
|
|
num_blocks = 10
|
|
full_nodes, wallets = two_wallet_nodes_five_freeze
|
|
full_node_api_0 = full_nodes[0]
|
|
full_node_0 = full_node_api_0.full_node
|
|
server_0 = full_node_0.server
|
|
|
|
wallet_node_0, wallet_0_server = wallets[0]
|
|
assert wallet_node_0.wallet_state_manager is not None
|
|
wallet_node_1, wallet_1_server = wallets[1]
|
|
assert wallet_node_1.wallet_state_manager is not None
|
|
|
|
wallet_0 = wallet_node_0.wallet_state_manager.main_wallet
|
|
wallet_1 = wallet_node_1.wallet_state_manager.main_wallet
|
|
ph = await wallet_0.get_new_puzzlehash()
|
|
if trusted:
|
|
wallet_node_0.config["trusted_peers"] = {server_0.node_id.hex(): server_0.node_id.hex()}
|
|
wallet_node_1.config["trusted_peers"] = {server_0.node_id.hex(): server_0.node_id.hex()}
|
|
else:
|
|
wallet_node_0.config["trusted_peers"] = {}
|
|
wallet_node_1.config["trusted_peers"] = {}
|
|
await wallet_0_server.start_client(PeerInfo(self_hostname, uint16(server_0._port)), None)
|
|
|
|
await wallet_1_server.start_client(PeerInfo(self_hostname, uint16(server_0._port)), None)
|
|
|
|
for i in range(0, num_blocks):
|
|
await full_node_api_0.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
|
|
funds = sum(
|
|
[calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i)) for i in range(1, num_blocks)]
|
|
)
|
|
await time_out_assert(20, wallet_is_synced, True, wallet_node_0, full_node_api_0)
|
|
await time_out_assert(20, wallet_0.get_confirmed_balance, funds)
|
|
await time_out_assert(20, wallet_0.get_unconfirmed_balance, funds)
|
|
|
|
assert await wallet_0.get_confirmed_balance() == funds
|
|
assert await wallet_0.get_unconfirmed_balance() == funds
|
|
|
|
tx = await wallet_0.generate_signed_transaction(
|
|
uint64(10),
|
|
await wallet_node_1.wallet_state_manager.main_wallet.get_new_puzzlehash(),
|
|
uint64(0),
|
|
)
|
|
|
|
await wallet_0.push_transaction(tx)
|
|
|
|
await time_out_assert(20, full_node_0.mempool_manager.get_spendbundle, tx.spend_bundle, tx.name)
|
|
# Full node height 11, wallet height 9
|
|
await time_out_assert(20, wallet_0.get_confirmed_balance, funds)
|
|
await time_out_assert(20, wallet_0.get_unconfirmed_balance, funds - 10)
|
|
|
|
for i in range(0, 4):
|
|
await full_node_api_0.farm_new_transaction_block(FarmNewBlockProtocol(bytes32(32 * b"0")))
|
|
|
|
# here it's num_blocks + 1 because our last reward is included in the first block that we just farmed
|
|
new_funds = sum(
|
|
[
|
|
calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i))
|
|
for i in range(1, num_blocks + 1)
|
|
]
|
|
)
|
|
|
|
# Full node height 17, wallet height 15
|
|
await time_out_assert(20, wallet_0.get_confirmed_balance, new_funds - 10)
|
|
await time_out_assert(20, wallet_0.get_unconfirmed_balance, new_funds - 10)
|
|
await time_out_assert(20, wallet_1.get_confirmed_balance, 10)
|
|
|
|
tx = await wallet_1.generate_signed_transaction(uint64(5), await wallet_0.get_new_puzzlehash(), uint64(0))
|
|
await wallet_1.push_transaction(tx)
|
|
await time_out_assert(20, full_node_0.mempool_manager.get_spendbundle, tx.spend_bundle, tx.name)
|
|
|
|
for i in range(0, 4):
|
|
await full_node_api_0.farm_new_transaction_block(FarmNewBlockProtocol(bytes32(32 * b"0")))
|
|
|
|
await wallet_0.get_confirmed_balance()
|
|
await wallet_0.get_unconfirmed_balance()
|
|
await wallet_1.get_confirmed_balance()
|
|
|
|
await time_out_assert(20, wallet_0.get_confirmed_balance, new_funds - 5)
|
|
await time_out_assert(20, wallet_0.get_unconfirmed_balance, new_funds - 5)
|
|
await time_out_assert(20, wallet_1.get_confirmed_balance, 5)
|
|
|
|
# @pytest.mark.asyncio
|
|
# async def test_wallet_finds_full_node(self):
|
|
# node_iters = [
|
|
# setup_full_node(
|
|
# test_constants,
|
|
# "blockchain_test.db",
|
|
# 11234,
|
|
# introducer_port=11236,
|
|
# simulator=False,
|
|
# ),
|
|
# setup_wallet_node(
|
|
# 11235,
|
|
# test_constants,
|
|
# None,
|
|
# introducer_port=11236,
|
|
# ),
|
|
# setup_introducer(11236),
|
|
# ]
|
|
#
|
|
# full_node_api = await node_iters[0].__anext__()
|
|
# wallet, wallet_server = await node_iters[1].__anext__()
|
|
# introducer, introducer_server = await node_iters[2].__anext__()
|
|
#
|
|
# async def has_full_node():
|
|
# outbound: List[WSChiaConnection] = wallet.server.get_outgoing_connections()
|
|
# for connection in outbound:
|
|
# if connection.connection_type is NodeType.FULL_NODE:
|
|
# return True
|
|
# return False
|
|
#
|
|
# await time_out_assert(
|
|
# 2 * 60,
|
|
# has_full_node,
|
|
# True,
|
|
# )
|
|
# await _teardown_nodes(node_iters)
|
|
@pytest.mark.parametrize(
|
|
"trusted",
|
|
[True, False],
|
|
)
|
|
@pytest.mark.asyncio
|
|
async def test_wallet_make_transaction_with_fee(
|
|
self,
|
|
two_wallet_nodes: Tuple[List[FullNodeSimulator], List[Tuple[WalletNode, ChiaServer]]],
|
|
trusted: bool,
|
|
self_hostname: str,
|
|
) -> None:
|
|
num_blocks = 5
|
|
full_nodes, wallets = two_wallet_nodes
|
|
full_node_1 = full_nodes[0]
|
|
|
|
wallet_node, server_2 = wallets[0]
|
|
assert wallet_node.wallet_state_manager is not None
|
|
wallet_node_2, server_3 = wallets[1]
|
|
assert wallet_node_2.wallet_state_manager is not None
|
|
|
|
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
ph = await wallet.get_new_puzzlehash()
|
|
if trusted:
|
|
wallet_node.config["trusted_peers"] = {
|
|
full_node_1.full_node.server.node_id.hex(): full_node_1.full_node.server.node_id.hex()
|
|
}
|
|
wallet_node_2.config["trusted_peers"] = {
|
|
full_node_1.full_node.server.node_id.hex(): full_node_1.full_node.server.node_id.hex()
|
|
}
|
|
else:
|
|
wallet_node.config["trusted_peers"] = {}
|
|
wallet_node_2.config["trusted_peers"] = {}
|
|
await server_2.start_client(PeerInfo(self_hostname, uint16(full_node_1.full_node.server._port)), None)
|
|
|
|
for i in range(0, num_blocks):
|
|
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
|
|
funds = sum(
|
|
[calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i)) for i in range(1, num_blocks)]
|
|
)
|
|
|
|
await time_out_assert(5, wallet.get_confirmed_balance, funds)
|
|
await time_out_assert(5, wallet.get_unconfirmed_balance, funds)
|
|
|
|
assert await wallet.get_confirmed_balance() == funds
|
|
assert await wallet.get_unconfirmed_balance() == funds
|
|
tx_amount = 3200000000000
|
|
tx_fee = 10
|
|
tx = await wallet.generate_signed_transaction(
|
|
uint64(tx_amount),
|
|
await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash(),
|
|
uint64(tx_fee),
|
|
)
|
|
assert tx.spend_bundle is not None
|
|
|
|
fees = tx.spend_bundle.fees()
|
|
assert fees == tx_fee
|
|
|
|
await wallet.push_transaction(tx)
|
|
await time_out_assert(5, full_node_1.full_node.mempool_manager.get_spendbundle, tx.spend_bundle, tx.name)
|
|
|
|
await time_out_assert(5, wallet.get_confirmed_balance, funds)
|
|
await time_out_assert(5, wallet.get_unconfirmed_balance, funds - tx_amount - tx_fee)
|
|
|
|
for i in range(0, num_blocks):
|
|
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(bytes32(32 * b"0")))
|
|
|
|
new_funds = sum(
|
|
[
|
|
calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i))
|
|
for i in range(1, num_blocks + 1)
|
|
]
|
|
)
|
|
|
|
await time_out_assert(5, wallet.get_confirmed_balance, new_funds - tx_amount - tx_fee)
|
|
await time_out_assert(5, wallet.get_unconfirmed_balance, new_funds - tx_amount - tx_fee)
|
|
|
|
@pytest.mark.parametrize(
|
|
"trusted",
|
|
[True, False],
|
|
)
|
|
@pytest.mark.asyncio
|
|
async def test_wallet_create_hit_max_send_amount(
|
|
self,
|
|
two_wallet_nodes: Tuple[List[FullNodeSimulator], List[Tuple[WalletNode, ChiaServer]]],
|
|
trusted: bool,
|
|
self_hostname: str,
|
|
) -> None:
|
|
num_blocks = 5
|
|
full_nodes, wallets = two_wallet_nodes
|
|
full_node_1 = full_nodes[0]
|
|
|
|
wallet_node, server_2 = wallets[0]
|
|
assert wallet_node.wallet_state_manager is not None
|
|
wallet_node_2, server_3 = wallets[1]
|
|
|
|
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
ph = await wallet.get_new_puzzlehash()
|
|
if trusted:
|
|
wallet_node.config["trusted_peers"] = {
|
|
full_node_1.full_node.server.node_id.hex(): full_node_1.full_node.server.node_id.hex()
|
|
}
|
|
wallet_node_2.config["trusted_peers"] = {
|
|
full_node_1.full_node.server.node_id.hex(): full_node_1.full_node.server.node_id.hex()
|
|
}
|
|
else:
|
|
wallet_node.config["trusted_peers"] = {}
|
|
wallet_node_2.config["trusted_peers"] = {}
|
|
await server_2.start_client(PeerInfo(self_hostname, uint16(full_node_1.full_node.server._port)), None)
|
|
|
|
for i in range(0, num_blocks):
|
|
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
|
|
funds = sum(
|
|
[calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i)) for i in range(1, num_blocks)]
|
|
)
|
|
|
|
await time_out_assert(5, wallet.get_confirmed_balance, funds)
|
|
|
|
primaries: List[AmountWithPuzzlehash] = []
|
|
for i in range(0, 60):
|
|
primaries.append({"puzzlehash": ph, "amount": uint64(1000000000 + i), "memos": []})
|
|
|
|
tx_split_coins = await wallet.generate_signed_transaction(uint64(1), ph, uint64(0), primaries=primaries)
|
|
assert tx_split_coins.spend_bundle is not None
|
|
|
|
await wallet.push_transaction(tx_split_coins)
|
|
await time_out_assert(
|
|
15, tx_in_pool, True, full_node_1.full_node.mempool_manager, tx_split_coins.spend_bundle.name()
|
|
)
|
|
for i in range(0, num_blocks):
|
|
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(bytes32(32 * b"0")))
|
|
|
|
funds = sum(
|
|
[
|
|
calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i))
|
|
for i in range(1, num_blocks + 1)
|
|
]
|
|
)
|
|
|
|
await time_out_assert(90, wallet.get_confirmed_balance, funds)
|
|
max_sent_amount = await wallet.get_max_send_amount()
|
|
|
|
# 1) Generate transaction that is under the limit
|
|
under_limit_tx = None
|
|
try:
|
|
under_limit_tx = await wallet.generate_signed_transaction(
|
|
uint64(max_sent_amount - 1),
|
|
ph,
|
|
uint64(0),
|
|
)
|
|
except ValueError:
|
|
assert ValueError
|
|
|
|
assert under_limit_tx is not None
|
|
|
|
# 2) Generate transaction that is equal to limit
|
|
at_limit_tx = None
|
|
try:
|
|
at_limit_tx = await wallet.generate_signed_transaction(
|
|
uint64(max_sent_amount),
|
|
ph,
|
|
uint64(0),
|
|
)
|
|
except ValueError:
|
|
assert ValueError
|
|
|
|
assert at_limit_tx is not None
|
|
|
|
# 3) Generate transaction that is greater than limit
|
|
above_limit_tx = None
|
|
try:
|
|
above_limit_tx = await wallet.generate_signed_transaction(
|
|
uint64(max_sent_amount + 1),
|
|
ph,
|
|
uint64(0),
|
|
)
|
|
except ValueError:
|
|
pass
|
|
|
|
assert above_limit_tx is None
|
|
|
|
@pytest.mark.parametrize(
|
|
"trusted",
|
|
[True, False],
|
|
)
|
|
@pytest.mark.asyncio
|
|
async def test_wallet_prevent_fee_theft(
|
|
self,
|
|
two_wallet_nodes: Tuple[List[FullNodeSimulator], List[Tuple[WalletNode, ChiaServer]]],
|
|
trusted: bool,
|
|
self_hostname: str,
|
|
) -> None:
|
|
num_blocks = 5
|
|
full_nodes, wallets = two_wallet_nodes
|
|
full_node_1 = full_nodes[0]
|
|
|
|
wallet_node, server_2 = wallets[0]
|
|
assert wallet_node.wallet_state_manager is not None
|
|
wallet_node_2, server_3 = wallets[1]
|
|
assert wallet_node_2.wallet_state_manager is not None
|
|
|
|
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
ph = await wallet.get_new_puzzlehash()
|
|
if trusted:
|
|
wallet_node.config["trusted_peers"] = {
|
|
full_node_1.full_node.server.node_id.hex(): full_node_1.full_node.server.node_id.hex()
|
|
}
|
|
wallet_node_2.config["trusted_peers"] = {
|
|
full_node_1.full_node.server.node_id.hex(): full_node_1.full_node.server.node_id.hex()
|
|
}
|
|
else:
|
|
wallet_node.config["trusted_peers"] = {}
|
|
wallet_node_2.config["trusted_peers"] = {}
|
|
await server_2.start_client(PeerInfo(self_hostname, uint16(full_node_1.full_node.server._port)), None)
|
|
|
|
for i in range(0, num_blocks):
|
|
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
|
|
funds = sum(
|
|
[calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i)) for i in range(1, num_blocks)]
|
|
)
|
|
|
|
await time_out_assert(5, wallet.get_confirmed_balance, funds)
|
|
await time_out_assert(5, wallet.get_unconfirmed_balance, funds)
|
|
|
|
assert await wallet.get_confirmed_balance() == funds
|
|
assert await wallet.get_unconfirmed_balance() == funds
|
|
tx_amount = 3200000000000
|
|
tx_fee = 300000000000
|
|
tx = await wallet.generate_signed_transaction(
|
|
uint64(tx_amount),
|
|
await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash(),
|
|
uint64(tx_fee),
|
|
)
|
|
assert tx.spend_bundle is not None
|
|
|
|
# extract coin_spend from generated spend_bundle
|
|
for cs in tx.spend_bundle.coin_spends:
|
|
if cs.additions() == []:
|
|
stolen_cs = cs
|
|
# get a legit signature
|
|
stolen_sb = await wallet.sign_transaction([stolen_cs])
|
|
now = uint64(int(time.time()))
|
|
add_list = list(stolen_sb.additions())
|
|
rem_list = list(stolen_sb.removals())
|
|
name = stolen_sb.name()
|
|
stolen_tx = TransactionRecord(
|
|
confirmed_at_height=uint32(0),
|
|
created_at_time=now,
|
|
to_puzzle_hash=bytes32(32 * b"0"),
|
|
amount=uint64(0),
|
|
fee_amount=stolen_cs.coin.amount,
|
|
confirmed=False,
|
|
sent=uint32(0),
|
|
spend_bundle=stolen_sb,
|
|
additions=add_list,
|
|
removals=rem_list,
|
|
wallet_id=wallet.id(),
|
|
sent_to=[],
|
|
trade_id=None,
|
|
type=uint32(TransactionType.OUTGOING_TX.value),
|
|
name=name,
|
|
memos=list(compute_memos(stolen_sb).items()),
|
|
)
|
|
await wallet.push_transaction(stolen_tx)
|
|
|
|
await time_out_assert(5, wallet.get_confirmed_balance, funds)
|
|
await time_out_assert(5, wallet.get_unconfirmed_balance, funds - stolen_cs.coin.amount)
|
|
|
|
for i in range(0, num_blocks):
|
|
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(bytes32(32 * b"0")))
|
|
|
|
# Funds have not decreased because stolen_tx was rejected
|
|
outstanding_coinbase_rewards = 2000000000000
|
|
await time_out_assert(20, wallet.get_confirmed_balance, funds + outstanding_coinbase_rewards)
|
|
|
|
@pytest.mark.parametrize(
|
|
"trusted",
|
|
[True, False],
|
|
)
|
|
@pytest.mark.asyncio
|
|
async def test_wallet_tx_reorg(
|
|
self,
|
|
two_wallet_nodes: Tuple[List[FullNodeSimulator], List[Tuple[WalletNode, ChiaServer]]],
|
|
trusted: bool,
|
|
self_hostname: str,
|
|
) -> None:
|
|
num_blocks = 5
|
|
full_nodes, wallets = two_wallet_nodes
|
|
full_node_api = full_nodes[0]
|
|
fn_server = full_node_api.full_node.server
|
|
|
|
wallet_node, server_2 = wallets[0]
|
|
assert wallet_node.wallet_state_manager is not None
|
|
wallet_node_2, server_3 = wallets[1]
|
|
assert wallet_node_2.wallet_state_manager is not None
|
|
|
|
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
wallet_2 = wallet_node_2.wallet_state_manager.main_wallet
|
|
|
|
ph = await wallet.get_new_puzzlehash()
|
|
ph2 = await wallet_2.get_new_puzzlehash()
|
|
if trusted:
|
|
wallet_node.config["trusted_peers"] = {fn_server.node_id.hex(): fn_server.node_id.hex()}
|
|
wallet_node_2.config["trusted_peers"] = {fn_server.node_id.hex(): fn_server.node_id.hex()}
|
|
else:
|
|
wallet_node.config["trusted_peers"] = {}
|
|
wallet_node_2.config["trusted_peers"] = {}
|
|
|
|
await server_2.start_client(PeerInfo(self_hostname, uint16(fn_server._port)), None)
|
|
await server_3.start_client(PeerInfo(self_hostname, uint16(fn_server._port)), None)
|
|
for i in range(0, num_blocks):
|
|
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
|
|
funds = sum(
|
|
[calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i)) for i in range(1, num_blocks)]
|
|
)
|
|
# Waits a few seconds to receive rewards
|
|
all_blocks = await full_node_api.get_all_full_blocks()
|
|
|
|
# Ensure that we use a coin that we will not reorg out
|
|
coin = list(all_blocks[-3].get_included_reward_coins())[0]
|
|
await asyncio.sleep(5)
|
|
|
|
tx = await wallet.generate_signed_transaction(uint64(1000), ph2, coins={coin})
|
|
assert tx.spend_bundle is not None
|
|
await wallet.push_transaction(tx)
|
|
await full_node_api.full_node.respond_transaction(tx.spend_bundle, tx.name)
|
|
await time_out_assert(5, full_node_api.full_node.mempool_manager.get_spendbundle, tx.spend_bundle, tx.name)
|
|
await time_out_assert(5, wallet.get_confirmed_balance, funds)
|
|
for i in range(0, 2):
|
|
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(bytes32(32 * b"0")))
|
|
await time_out_assert(5, wallet_2.get_confirmed_balance, 1000)
|
|
funds -= 1000
|
|
|
|
await time_out_assert(5, wallet_node.wallet_state_manager.blockchain.get_peak_height, 7)
|
|
peak = full_node_api.full_node.blockchain.get_peak()
|
|
assert peak is not None
|
|
peak_height = peak.height
|
|
print(peak_height)
|
|
|
|
# Perform a reorg, which will revert the transaction in the full node and wallet, and cause wallet to resubmit
|
|
await full_node_api.reorg_from_index_to_new_index(
|
|
ReorgProtocol(uint32(peak_height - 3), uint32(peak_height + 3), bytes32(32 * b"0"))
|
|
)
|
|
|
|
funds = sum(
|
|
[
|
|
calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i))
|
|
for i in range(1, peak_height - 2)
|
|
]
|
|
)
|
|
|
|
await time_out_assert(7, full_node_api.full_node.blockchain.get_peak_height, peak_height + 3)
|
|
await time_out_assert(7, wallet_node.wallet_state_manager.blockchain.get_peak_height, peak_height + 3)
|
|
|
|
# Farm a few blocks so we can confirm the resubmitted transaction
|
|
for i in range(0, num_blocks):
|
|
await asyncio.sleep(1)
|
|
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(bytes32(32 * b"0")))
|
|
|
|
# By this point, the transaction should be confirmed
|
|
await time_out_assert(15, wallet.get_confirmed_balance, funds - 1000)
|
|
|
|
unconfirmed = await wallet_node.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(int(wallet.id()))
|
|
assert len(unconfirmed) == 0
|
|
tx_record = await wallet_node.wallet_state_manager.tx_store.get_transaction_record(tx.name)
|
|
assert tx_record is not None
|
|
removed = tx_record.removals[0]
|
|
added = tx_record.additions[0]
|
|
added_1 = tx_record.additions[1]
|
|
wallet_coin_record_rem = await wallet_node.wallet_state_manager.coin_store.get_coin_record(removed.name())
|
|
assert wallet_coin_record_rem is not None
|
|
assert wallet_coin_record_rem.spent
|
|
|
|
coin_record_full_node = await full_node_api.full_node.coin_store.get_coin_record(removed.name())
|
|
assert coin_record_full_node is not None
|
|
assert coin_record_full_node.spent
|
|
add_1_coin_record_full_node = await full_node_api.full_node.coin_store.get_coin_record(added.name())
|
|
assert add_1_coin_record_full_node is not None
|
|
assert add_1_coin_record_full_node.confirmed_block_index > 0
|
|
add_2_coin_record_full_node = await full_node_api.full_node.coin_store.get_coin_record(added_1.name())
|
|
assert add_2_coin_record_full_node is not None
|
|
assert add_2_coin_record_full_node.confirmed_block_index > 0
|
|
|
|
@pytest.mark.parametrize(
|
|
"trusted",
|
|
[False],
|
|
)
|
|
@pytest.mark.asyncio
|
|
async def test_address_sliding_window(
|
|
self,
|
|
wallet_node_100_pk: Tuple[List[FullNodeSimulator], List[Tuple[WalletNode, ChiaServer]]],
|
|
trusted: bool,
|
|
self_hostname: str,
|
|
) -> None:
|
|
full_nodes, wallets = wallet_node_100_pk
|
|
full_node_api = full_nodes[0]
|
|
server_1: ChiaServer = full_node_api.full_node.server
|
|
wallet_node, server_2 = wallets[0]
|
|
assert wallet_node.wallet_state_manager is not None
|
|
if trusted:
|
|
wallet_node.config["trusted_peers"] = {server_1.node_id.hex(): server_1.node_id.hex()}
|
|
else:
|
|
wallet_node.config["trusted_peers"] = {}
|
|
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
|
|
await server_2.start_client(PeerInfo(self_hostname, uint16(server_1._port)), None)
|
|
|
|
puzzle_hashes = []
|
|
for i in range(211):
|
|
pubkey = master_sk_to_wallet_sk(wallet_node.wallet_state_manager.private_key, uint32(i)).get_g1()
|
|
puzzle: Program = wallet.puzzle_for_pk(bytes(pubkey))
|
|
puzzle_hash: bytes32 = puzzle.get_tree_hash()
|
|
puzzle_hashes.append(puzzle_hash)
|
|
|
|
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(bytes32(32 * b"0")))
|
|
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hashes[0]))
|
|
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hashes[210]))
|
|
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hashes[114]))
|
|
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(bytes32(32 * b"0")))
|
|
|
|
await time_out_assert(60, wallet.get_confirmed_balance, 2 * 10 ** 12)
|
|
|
|
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hashes[50]))
|
|
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(bytes32(32 * b"0")))
|
|
|
|
await time_out_assert(60, wallet.get_confirmed_balance, 8 * 10 ** 12)
|
|
|
|
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hashes[113]))
|
|
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hashes[209]))
|
|
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(bytes32(32 * b"0")))
|
|
await time_out_assert(60, wallet.get_confirmed_balance, 12 * 10 ** 12)
|
|
|
|
@pytest.mark.parametrize(
|
|
"trusted",
|
|
[True, False],
|
|
)
|
|
@pytest.mark.asyncio
|
|
async def test_wallet_transaction_options(
|
|
self,
|
|
two_wallet_nodes: Tuple[List[FullNodeSimulator], List[Tuple[WalletNode, ChiaServer]]],
|
|
trusted: bool,
|
|
self_hostname: str,
|
|
) -> None:
|
|
num_blocks = 5
|
|
full_nodes, wallets = two_wallet_nodes
|
|
full_node_api = full_nodes[0]
|
|
server_1 = full_node_api.full_node.server
|
|
|
|
wallet_node, server_2 = wallets[0]
|
|
assert wallet_node.wallet_state_manager is not None
|
|
wallet_node_2, server_3 = wallets[1]
|
|
assert wallet_node_2.wallet_state_manager is not None
|
|
|
|
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
ph = await wallet.get_new_puzzlehash()
|
|
if trusted:
|
|
wallet_node.config["trusted_peers"] = {server_1.node_id.hex(): server_1.node_id.hex()}
|
|
wallet_node_2.config["trusted_peers"] = {server_1.node_id.hex(): server_1.node_id.hex()}
|
|
else:
|
|
wallet_node.config["trusted_peers"] = {}
|
|
wallet_node_2.config["trusted_peers"] = {}
|
|
|
|
await server_2.start_client(PeerInfo(self_hostname, uint16(server_1._port)), None)
|
|
|
|
for i in range(0, num_blocks):
|
|
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(bytes32([0] * 32)))
|
|
|
|
funds = sum(
|
|
[
|
|
calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i))
|
|
for i in range(1, num_blocks + 1)
|
|
]
|
|
)
|
|
|
|
await time_out_assert(5, wallet.get_confirmed_balance, funds)
|
|
await time_out_assert(5, wallet.get_unconfirmed_balance, funds)
|
|
|
|
AMOUNT_TO_SEND = 4000000000000
|
|
coins = await wallet.select_coins(uint64(AMOUNT_TO_SEND))
|
|
coin_list = list(coins)
|
|
|
|
tx = await wallet.generate_signed_transaction(
|
|
uint64(AMOUNT_TO_SEND),
|
|
await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash(),
|
|
uint64(0),
|
|
coins=coins,
|
|
origin_id=coin_list[2].name(),
|
|
)
|
|
assert tx.spend_bundle is not None
|
|
paid_coin = [coin for coin in tx.spend_bundle.additions() if coin.amount == AMOUNT_TO_SEND][0]
|
|
assert paid_coin.parent_coin_info == coin_list[2].name()
|
|
await wallet.push_transaction(tx)
|
|
|
|
await time_out_assert(5, wallet.get_confirmed_balance, funds)
|
|
await time_out_assert(5, wallet.get_unconfirmed_balance, funds - AMOUNT_TO_SEND)
|
|
await time_out_assert(5, full_node_api.full_node.mempool_manager.get_spendbundle, tx.spend_bundle, tx.name)
|
|
|
|
for i in range(0, num_blocks):
|
|
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(bytes32([0] * 32)))
|
|
|
|
await time_out_assert(5, wallet.get_confirmed_balance, funds - AMOUNT_TO_SEND)
|
|
await time_out_assert(5, wallet.get_unconfirmed_balance, funds - AMOUNT_TO_SEND)
|