388 lines
13 KiB
Python
388 lines
13 KiB
Python
import asyncio
|
|
from secrets import token_bytes
|
|
|
|
import pytest
|
|
|
|
from src.protocols import full_node_protocol
|
|
from src.simulator.simulator_protocol import FarmNewBlockProtocol, ReorgProtocol
|
|
from src.types.peer_info import PeerInfo
|
|
from src.util.ints import uint16, uint32
|
|
from tests.setup_nodes import setup_simulators_and_wallets
|
|
from src.consensus.block_rewards import calculate_base_fee, calculate_block_reward
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def event_loop():
|
|
loop = asyncio.get_event_loop()
|
|
yield loop
|
|
|
|
|
|
class TestWalletSimulator:
|
|
@pytest.fixture(scope="function")
|
|
async def wallet_node(self):
|
|
async for _ in setup_simulators_and_wallets(1, 1, {}):
|
|
yield _
|
|
|
|
@pytest.fixture(scope="function")
|
|
async def two_wallet_nodes(self):
|
|
async for _ in setup_simulators_and_wallets(
|
|
1, 2, {"COINBASE_FREEZE_PERIOD": 0}
|
|
):
|
|
yield _
|
|
|
|
@pytest.fixture(scope="function")
|
|
async def two_wallet_nodes_five_freeze(self):
|
|
async for _ in setup_simulators_and_wallets(
|
|
1, 2, {"COINBASE_FREEZE_PERIOD": 5}
|
|
):
|
|
yield _
|
|
|
|
@pytest.fixture(scope="function")
|
|
async def three_sim_two_wallets(self):
|
|
async for _ in setup_simulators_and_wallets(
|
|
3, 2, {"COINBASE_FREEZE_PERIOD": 0}
|
|
):
|
|
yield _
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_wallet_coinbase(self, wallet_node):
|
|
num_blocks = 5
|
|
full_nodes, wallets = wallet_node
|
|
full_node_1, server_1 = full_nodes[0]
|
|
wallet_node, server_2 = wallets[0]
|
|
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
ph = await wallet.get_new_puzzlehash()
|
|
|
|
await server_2.start_client(PeerInfo("localhost", uint16(server_1._port)), None)
|
|
for i in range(1, num_blocks):
|
|
await full_node_1.farm_new_block(FarmNewBlockProtocol(ph))
|
|
|
|
await asyncio.sleep(3)
|
|
funds = sum(
|
|
[
|
|
calculate_base_fee(uint32(i)) + calculate_block_reward(uint32(i))
|
|
for i in range(1, num_blocks - 2)
|
|
]
|
|
)
|
|
assert await wallet.get_confirmed_balance() == funds
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_wallet_make_transaction(self, two_wallet_nodes):
|
|
num_blocks = 5
|
|
full_nodes, wallets = two_wallet_nodes
|
|
full_node_1, server_1 = full_nodes[0]
|
|
wallet_node, server_2 = wallets[0]
|
|
wallet_node_2, server_3 = wallets[1]
|
|
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
ph = await wallet.get_new_puzzlehash()
|
|
|
|
await server_2.start_client(PeerInfo("localhost", uint16(server_1._port)), None)
|
|
|
|
for i in range(0, num_blocks):
|
|
await full_node_1.farm_new_block(FarmNewBlockProtocol(ph))
|
|
|
|
funds = sum(
|
|
[
|
|
calculate_base_fee(uint32(i)) + calculate_block_reward(uint32(i))
|
|
for i in range(1, num_blocks - 1)
|
|
]
|
|
)
|
|
|
|
await asyncio.sleep(2)
|
|
|
|
assert await wallet.get_confirmed_balance() == funds
|
|
assert await wallet.get_unconfirmed_balance() == funds
|
|
|
|
tx = await wallet.generate_signed_transaction(
|
|
10,
|
|
await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash(),
|
|
0,
|
|
)
|
|
await wallet.push_transaction(tx)
|
|
|
|
await asyncio.sleep(2)
|
|
confirmed_balance = await wallet.get_confirmed_balance()
|
|
unconfirmed_balance = await wallet.get_unconfirmed_balance()
|
|
|
|
assert confirmed_balance == funds
|
|
assert unconfirmed_balance == funds - 10
|
|
|
|
for i in range(0, num_blocks):
|
|
await full_node_1.farm_new_block(FarmNewBlockProtocol(ph))
|
|
|
|
await asyncio.sleep(2)
|
|
|
|
new_funds = sum(
|
|
[
|
|
calculate_base_fee(uint32(i)) + calculate_block_reward(uint32(i))
|
|
for i in range(1, (2 * num_blocks) - 1)
|
|
]
|
|
)
|
|
|
|
confirmed_balance = await wallet.get_confirmed_balance()
|
|
unconfirmed_balance = await wallet.get_unconfirmed_balance()
|
|
|
|
assert confirmed_balance == new_funds - 10
|
|
assert unconfirmed_balance == new_funds - 10
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_wallet_coinbase_reorg(self, wallet_node):
|
|
num_blocks = 5
|
|
full_nodes, wallets = wallet_node
|
|
full_node_1, server_1 = full_nodes[0]
|
|
wallet_node, server_2 = wallets[0]
|
|
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
ph = await wallet.get_new_puzzlehash()
|
|
|
|
await server_2.start_client(PeerInfo("localhost", uint16(server_1._port)), None)
|
|
for i in range(1, num_blocks):
|
|
await full_node_1.farm_new_block(FarmNewBlockProtocol(ph))
|
|
|
|
await asyncio.sleep(3)
|
|
funds = sum(
|
|
[
|
|
calculate_base_fee(uint32(i)) + calculate_block_reward(uint32(i))
|
|
for i in range(1, num_blocks - 2)
|
|
]
|
|
)
|
|
assert await wallet.get_confirmed_balance() == funds
|
|
|
|
await full_node_1.reorg_from_index_to_new_index(
|
|
ReorgProtocol(uint32(5), uint32(num_blocks + 3), token_bytes())
|
|
)
|
|
await asyncio.sleep(3)
|
|
|
|
funds = sum(
|
|
[
|
|
calculate_base_fee(uint32(i)) + calculate_block_reward(uint32(i))
|
|
for i in range(1, 5)
|
|
]
|
|
)
|
|
|
|
assert await wallet.get_confirmed_balance() == funds
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_wallet_send_to_three_peers(self, three_sim_two_wallets):
|
|
num_blocks = 10
|
|
full_nodes, wallets = three_sim_two_wallets
|
|
|
|
wallet_0, wallet_server_0 = wallets[0]
|
|
full_node_0, server_0 = full_nodes[0]
|
|
full_node_1, server_1 = full_nodes[1]
|
|
full_node_2, server_2 = full_nodes[2]
|
|
|
|
ph = await wallet_0.wallet_state_manager.main_wallet.get_new_puzzlehash()
|
|
|
|
# wallet0 <-> sever0
|
|
await wallet_server_0.start_client(
|
|
PeerInfo("localhost", uint16(server_0._port)), None
|
|
)
|
|
|
|
for i in range(1, num_blocks):
|
|
await full_node_0.farm_new_block(FarmNewBlockProtocol(ph))
|
|
|
|
all_blocks = await full_node_0.get_current_blocks(full_node_0.get_tip())
|
|
|
|
for block in all_blocks:
|
|
async for _ in full_node_1.respond_block(
|
|
full_node_protocol.RespondBlock(block)
|
|
):
|
|
pass
|
|
async for _ in full_node_2.respond_block(
|
|
full_node_protocol.RespondBlock(block)
|
|
):
|
|
pass
|
|
|
|
await asyncio.sleep(2)
|
|
funds = sum(
|
|
[
|
|
calculate_base_fee(uint32(i)) + calculate_block_reward(uint32(i))
|
|
for i in range(1, num_blocks - 2)
|
|
]
|
|
)
|
|
assert (
|
|
await wallet_0.wallet_state_manager.main_wallet.get_confirmed_balance()
|
|
== funds
|
|
)
|
|
|
|
tx = await wallet_0.wallet_state_manager.main_wallet.generate_signed_transaction(
|
|
10, token_bytes(), 0
|
|
)
|
|
await wallet_0.wallet_state_manager.main_wallet.push_transaction(tx)
|
|
|
|
await asyncio.sleep(1)
|
|
|
|
bundle0 = full_node_0.mempool_manager.get_spendbundle(tx.name())
|
|
assert bundle0 is not None
|
|
|
|
# wallet0 <-> sever1
|
|
await wallet_server_0.start_client(
|
|
PeerInfo("localhost", uint16(server_1._port)), wallet_0._on_connect
|
|
)
|
|
await asyncio.sleep(1)
|
|
|
|
bundle1 = full_node_1.mempool_manager.get_spendbundle(tx.name())
|
|
assert bundle1 is not None
|
|
|
|
# wallet0 <-> sever2
|
|
await wallet_server_0.start_client(
|
|
PeerInfo("localhost", uint16(server_2._port)), wallet_0._on_connect
|
|
)
|
|
await asyncio.sleep(1)
|
|
|
|
bundle2 = full_node_2.mempool_manager.get_spendbundle(tx.name())
|
|
assert bundle2 is not None
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_wallet_make_transaction_hop(self, two_wallet_nodes_five_freeze):
|
|
num_blocks = 10
|
|
full_nodes, wallets = two_wallet_nodes_five_freeze
|
|
full_node_0, full_node_server = full_nodes[0]
|
|
wallet_node_0, wallet_0_server = wallets[0]
|
|
wallet_node_1, wallet_1_server = wallets[1]
|
|
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()
|
|
|
|
await wallet_0_server.start_client(
|
|
PeerInfo("localhost", uint16(full_node_server._port)), None
|
|
)
|
|
|
|
await wallet_1_server.start_client(
|
|
PeerInfo("localhost", uint16(full_node_server._port)), None
|
|
)
|
|
|
|
for i in range(0, num_blocks):
|
|
await full_node_0.farm_new_block(FarmNewBlockProtocol(ph))
|
|
|
|
funds = sum(
|
|
[
|
|
calculate_base_fee(uint32(i)) + calculate_block_reward(uint32(i))
|
|
for i in range(1, num_blocks - 1)
|
|
]
|
|
)
|
|
|
|
await asyncio.sleep(2)
|
|
|
|
assert await wallet_0.get_confirmed_balance() == funds
|
|
assert await wallet_0.get_unconfirmed_balance() == funds
|
|
|
|
tx = await wallet_0.generate_signed_transaction(
|
|
10,
|
|
await wallet_node_1.wallet_state_manager.main_wallet.get_new_puzzlehash(),
|
|
0,
|
|
)
|
|
|
|
await wallet_0.push_transaction(tx)
|
|
|
|
await asyncio.sleep(1)
|
|
# Full node height 11, wallet height 9
|
|
confirmed_balance = await wallet_0.get_confirmed_balance()
|
|
unconfirmed_balance = await wallet_0.get_unconfirmed_balance()
|
|
|
|
assert confirmed_balance == funds
|
|
assert unconfirmed_balance == funds - 10
|
|
|
|
for i in range(0, 7):
|
|
await full_node_0.farm_new_block(FarmNewBlockProtocol(token_bytes()))
|
|
|
|
await asyncio.sleep(1)
|
|
|
|
new_funds = sum(
|
|
[
|
|
calculate_base_fee(uint32(i)) + calculate_block_reward(uint32(i))
|
|
for i in range(1, num_blocks + 1)
|
|
]
|
|
)
|
|
|
|
# Full node height 17, wallet height 15
|
|
confirmed_balance = await wallet_0.get_confirmed_balance()
|
|
unconfirmed_balance = await wallet_0.get_unconfirmed_balance()
|
|
wallet_2_confirmed_balance = await wallet_1.get_confirmed_balance()
|
|
|
|
assert confirmed_balance == new_funds - 10
|
|
assert unconfirmed_balance == new_funds - 10
|
|
assert wallet_2_confirmed_balance == 10
|
|
|
|
tx = await wallet_1.generate_signed_transaction(
|
|
5, await wallet_0.get_new_puzzlehash(), 0
|
|
)
|
|
await wallet_1.push_transaction(tx)
|
|
|
|
for i in range(0, 7):
|
|
await full_node_0.farm_new_block(FarmNewBlockProtocol(token_bytes()))
|
|
|
|
await asyncio.sleep(1)
|
|
|
|
confirmed_balance = await wallet_0.get_confirmed_balance()
|
|
unconfirmed_balance = await wallet_0.get_unconfirmed_balance()
|
|
wallet_2_confirmed_balance = await wallet_1.get_confirmed_balance()
|
|
|
|
assert confirmed_balance == new_funds - 5
|
|
assert unconfirmed_balance == new_funds - 5
|
|
assert wallet_2_confirmed_balance == 5
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_wallet_make_transaction_with_fee(self, two_wallet_nodes):
|
|
num_blocks = 5
|
|
full_nodes, wallets = two_wallet_nodes
|
|
full_node_1, server_1 = full_nodes[0]
|
|
wallet_node, server_2 = wallets[0]
|
|
wallet_node_2, server_3 = wallets[1]
|
|
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
ph = await wallet.get_new_puzzlehash()
|
|
|
|
await server_2.start_client(PeerInfo("localhost", uint16(server_1._port)), None)
|
|
|
|
for i in range(0, num_blocks):
|
|
await full_node_1.farm_new_block(FarmNewBlockProtocol(ph))
|
|
|
|
funds = sum(
|
|
[
|
|
calculate_base_fee(uint32(i)) + calculate_block_reward(uint32(i))
|
|
for i in range(1, num_blocks - 1)
|
|
]
|
|
)
|
|
|
|
await asyncio.sleep(2)
|
|
|
|
assert await wallet.get_confirmed_balance() == funds
|
|
assert await wallet.get_unconfirmed_balance() == funds
|
|
tx_amount = 32000000000000
|
|
tx_fee = 10
|
|
tx = await wallet.generate_signed_transaction(
|
|
tx_amount,
|
|
await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash(),
|
|
tx_fee,
|
|
)
|
|
|
|
fees = tx.spend_bundle.fees()
|
|
assert fees == tx_fee
|
|
|
|
await wallet.push_transaction(tx)
|
|
|
|
await asyncio.sleep(2)
|
|
confirmed_balance = await wallet.get_confirmed_balance()
|
|
unconfirmed_balance = await wallet.get_unconfirmed_balance()
|
|
|
|
assert confirmed_balance == funds
|
|
assert unconfirmed_balance == funds - tx_amount - tx_fee
|
|
|
|
for i in range(0, num_blocks):
|
|
await full_node_1.farm_new_block(FarmNewBlockProtocol(token_bytes()))
|
|
|
|
await asyncio.sleep(2)
|
|
|
|
new_funds = sum(
|
|
[
|
|
calculate_base_fee(uint32(i)) + calculate_block_reward(uint32(i))
|
|
for i in range(1, num_blocks + 1)
|
|
]
|
|
)
|
|
|
|
confirmed_balance = await wallet.get_confirmed_balance()
|
|
unconfirmed_balance = await wallet.get_unconfirmed_balance()
|
|
|
|
assert confirmed_balance == new_funds - tx_amount - tx_fee
|
|
assert unconfirmed_balance == new_funds - tx_amount - tx_fee
|