async def setup_full_system(consensus_constants: ConsensusConstants, b_tools=None, b_tools_1=None, connect_to_daemon=False): if b_tools is None: b_tools = BlockTools(constants=test_constants) if b_tools_1 is None: b_tools_1 = BlockTools(constants=test_constants) node_iters = [ setup_introducer(21233), setup_harvester(21234, 21235, consensus_constants, b_tools), setup_farmer(21235, consensus_constants, b_tools, uint16(21237)), setup_vdf_clients(8000), setup_timelord(21236, 21237, False, consensus_constants, b_tools), setup_full_node(consensus_constants, "blockchain_test.db", 21237, b_tools, 21233, False, 10, True, connect_to_daemon), setup_full_node(consensus_constants, "blockchain_test_2.db", 21238, b_tools_1, 21233, False, 10, True, connect_to_daemon), setup_vdf_client(7999), setup_timelord(21239, 21238, True, consensus_constants, b_tools_1), ] introducer, introducer_server = await node_iters[0].__anext__() harvester, harvester_server = await node_iters[1].__anext__() farmer, farmer_server = await node_iters[2].__anext__() async def num_connections(): count = len(harvester.server.all_connections.items()) return count await time_out_assert_custom_interval(10, 3, num_connections, 1) vdf_clients = await node_iters[3].__anext__() timelord, timelord_server = await node_iters[4].__anext__() node_api_1 = await node_iters[5].__anext__() node_api_2 = await node_iters[6].__anext__() vdf_sanitizer = await node_iters[7].__anext__() sanitizer, sanitizer_server = await node_iters[8].__anext__() yield ( node_api_1, node_api_2, harvester, farmer, introducer, timelord, vdf_clients, vdf_sanitizer, sanitizer, node_api_1.full_node.server, ) await _teardown_nodes(node_iters)
async def setup_simulators_and_wallets( simulator_count: int, wallet_count: int, dic: Dict, starting_height=None, key_seed=None, starting_port=50000, ): simulators: List[FullNodeAPI] = [] wallets = [] node_iters = [] consensus_constants = constants_for_dic(dic) for index in range(0, simulator_count): port = starting_port + index db_name = f"blockchain_test_{port}.db" bt_tools = BlockTools(consensus_constants, const_dict=dic) # block tools modifies constants sim = setup_full_node( bt_tools.constants, db_name, port, bt_tools, simulator=True, ) simulators.append(await sim.__anext__()) node_iters.append(sim) for index in range(0, wallet_count): if key_seed is None: seed = std_hash(uint32(index)) else: seed = key_seed port = starting_port + 5000 + index bt_tools = BlockTools(consensus_constants, const_dict=dic) # block tools modifies constants wlt = setup_wallet_node( port, bt_tools.constants, bt_tools, None, key_seed=seed, starting_height=starting_height, ) wallets.append(await wlt.__anext__()) node_iters.append(wlt) yield simulators, wallets await _teardown_nodes(node_iters)
def test_json(self): bt = BlockTools() test_constants: Dict[str, Any] = { "DIFFICULTY_STARTING": 5, "DISCRIMINANT_SIZE_BITS": 16, "BLOCK_TIME_TARGET": 10, "MIN_BLOCK_TIME": 2, "DIFFICULTY_EPOCH": 12, # The number of blocks per epoch "DIFFICULTY_DELAY": 3, # EPOCH / WARP_FACTOR } block = bt.create_genesis_block(test_constants, bytes([0] * 32), b"0") dict_block = block.to_json_dict() assert FullBlock.from_json_dict(dict_block) == block
async def test_generator_hash(self, initial_blockchain): blocks, b = initial_blockchain new_header_data = HeaderData( blocks[9].header.data.height, blocks[9].header.data.prev_header_hash, blocks[9].header.data.timestamp, blocks[9].header.data.filter_hash, blocks[9].header.data.proof_of_space_hash, blocks[9].header.data.weight, blocks[9].header.data.total_iters, blocks[9].header.data.additions_root, blocks[9].header.data.removals_root, blocks[9].header.data.coinbase, blocks[9].header.data.coinbase_signature, blocks[9].header.data.fees_coin, blocks[9].header.data.aggregated_signature, blocks[9].header.data.cost, blocks[9].header.data.extension_data, bytes([1] * 32), ) block_bad = FullBlock( blocks[9].proof_of_space, blocks[9].proof_of_time, Header( new_header_data, BlockTools.get_harvester_signature( new_header_data, blocks[9].proof_of_space.plot_pubkey), ), blocks[9].transactions_generator, blocks[9].transactions_filter, ) result, removed, error_code = await b.receive_block(block_bad) assert result == ReceiveBlockResult.INVALID_BLOCK assert error_code == Err.INVALID_TRANSACTIONS_GENERATOR_HASH
async def setup_two_nodes(consensus_constants: ConsensusConstants): """ Setup and teardown of two full nodes, with blockchains and separate DBs. """ node_iters = [ setup_full_node(consensus_constants, "blockchain_test.db", 21234, BlockTools(constants=test_constants), simulator=False), setup_full_node(consensus_constants, "blockchain_test_2.db", 21235, BlockTools(constants=test_constants), simulator=False), ] fn1 = await node_iters[0].__anext__() fn2 = await node_iters[1].__anext__() yield fn1, fn2, fn1.full_node.server, fn2.full_node.server await _teardown_nodes(node_iters)
def main() -> None: config = load_config_cli(DEFAULT_ROOT_PATH, "config.yaml", SERVICE_NAME) config["database_path"] = config["simulator_database_path"] config["peer_db_path"] = config["simulator_peer_db_path"] config["introducer_peer"]["host"] = "127.0.0.1" config["introducer_peer"]["port"] = 58555 config["selected_network"] = "testnet0" config["simulation"] = True kwargs = service_kwargs_for_full_node_simulator( DEFAULT_ROOT_PATH, config, BlockTools(test_constants), ) return run_service(**kwargs)
async def test_invalid_pos_hash(self, initial_blockchain): blocks, b = initial_blockchain bad_pos_proof = bytearray([i for i in blocks[9].proof_of_space.proof]) bad_pos_proof[0] = uint8((bad_pos_proof[0] + 1) % 256) bad_pos = ProofOfSpace( blocks[9].proof_of_space.challenge_hash, blocks[9].proof_of_space.pool_pubkey, blocks[9].proof_of_space.plot_pubkey, blocks[9].proof_of_space.size, bytes(bad_pos_proof), ) new_header_data = HeaderData( blocks[9].header.data.height, blocks[9].header.data.prev_header_hash, blocks[9].header.data.timestamp, blocks[9].header.data.filter_hash, bad_pos.get_hash(), blocks[9].header.data.weight, blocks[9].header.data.total_iters, blocks[9].header.data.additions_root, blocks[9].header.data.removals_root, blocks[9].header.data.coinbase, blocks[9].header.data.coinbase_signature, blocks[9].header.data.fees_coin, blocks[9].header.data.aggregated_signature, blocks[9].header.data.cost, blocks[9].header.data.extension_data, blocks[9].header.data.generator_hash, ) # Proof of space has invalid block_bad = FullBlock( blocks[9].proof_of_space, blocks[9].proof_of_time, Header( new_header_data, BlockTools.get_harvester_signature( new_header_data, blocks[9].proof_of_space.plot_pubkey), ), blocks[9].transactions_generator, blocks[9].transactions_filter, ) result, removed, error_code = await b.receive_block(block_bad) assert result == ReceiveBlockResult.INVALID_BLOCK assert error_code == Err.INVALID_POSPACE_HASH
async def test_invalid_coinbase_signature(self, initial_blockchain): blocks, b = initial_blockchain coinbase_coin, coinbase_signature = create_coinbase_coin_and_signature( blocks[9].header.data.height, blocks[9].header.data.coinbase.puzzle_hash, uint64(9991), bt.pool_sk, ) new_header_data = HeaderData( blocks[9].header.data.height, blocks[9].header.data.prev_header_hash, blocks[9].header.data.timestamp, blocks[9].header.data.filter_hash, blocks[9].header.data.proof_of_space_hash, blocks[9].header.data.weight, blocks[9].header.data.total_iters, blocks[9].header.data.additions_root, blocks[9].header.data.removals_root, blocks[9].header.data.coinbase, coinbase_signature, blocks[9].header.data.fees_coin, blocks[9].header.data.aggregated_signature, blocks[9].header.data.cost, blocks[9].header.data.extension_data, blocks[9].header.data.generator_hash, ) # Coinbase amount invalid block_bad = FullBlock( blocks[9].proof_of_space, blocks[9].proof_of_time, Header( new_header_data, BlockTools.get_harvester_signature( new_header_data, blocks[9].proof_of_space.plot_pubkey), ), blocks[9].transactions_generator, blocks[9].transactions_filter, ) result, removed, error_code = await b.receive_block(block_bad) assert result == ReceiveBlockResult.INVALID_BLOCK assert error_code == Err.INVALID_COINBASE_SIGNATURE
async def setup_n_nodes(consensus_constants: ConsensusConstants, n: int): """ Setup and teardown of two full nodes, with blockchains and separate DBs. """ port_start = 21244 node_iters = [] for i in range(n): node_iters.append( setup_full_node( consensus_constants, f"blockchain_test_{i}.db", port_start + i, BlockTools(constants=test_constants), simulator=False, )) nodes = [] for ni in node_iters: nodes.append(await ni.__anext__()) yield nodes await _teardown_nodes(node_iters)
async def setup_node_and_wallet(consensus_constants: ConsensusConstants, starting_height=None, key_seed=None): btools = BlockTools(constants=test_constants) node_iters = [ setup_full_node(consensus_constants, "blockchain_test.db", 21234, btools, simulator=False), setup_wallet_node(21235, consensus_constants, btools, None, starting_height=starting_height, key_seed=key_seed), ] full_node_api = await node_iters[0].__anext__() wallet, s2 = await node_iters[1].__anext__() yield full_node_api, wallet, full_node_api.full_node.server, s2 await _teardown_nodes(node_iters)
from chia.server.start_harvester import service_kwargs_for_harvester from chia.server.start_introducer import service_kwargs_for_introducer from chia.server.start_service import Service from chia.server.start_timelord import service_kwargs_for_timelord from chia.server.start_wallet import service_kwargs_for_wallet from chia.simulator.start_simulator import service_kwargs_for_full_node_simulator from chia.timelord.timelord_launcher import kill_processes, spawn_process from chia.types.peer_info import PeerInfo from chia.util.bech32m import encode_puzzle_hash from tests.block_tools import BlockTools, test_constants from chia.util.hash import std_hash from chia.util.ints import uint16, uint32 from chia.util.keychain import Keychain, bytes_to_mnemonic from tests.time_out_assert import time_out_assert_custom_interval bt = BlockTools(constants=test_constants) self_hostname = bt.config["self_hostname"] def constants_for_dic(dic): return test_constants.replace(**dic) async def _teardown_nodes(node_aiters: List) -> None: awaitables = [node_iter.__anext__() for node_iter in node_aiters] for sublist_awaitable in asyncio.as_completed(awaitables): try: await sublist_awaitable except StopAsyncIteration: pass
wallet_protocol, ) from src.simulator.simulator_protocol import FarmNewBlockProtocol, ReorgProtocol from src.util.bundle_tools import best_solution_program from src.server.outbound_message import OutboundMessage from src.server.server import ChiaServer from src.types.full_block import FullBlock from src.types.spend_bundle import SpendBundle from src.types.header import Header from src.util.api_decorators import api_request from src.util.ints import uint64 from tests.block_tools import BlockTools OutboundMessageGenerator = AsyncGenerator[OutboundMessage, None] bt = BlockTools() class FullNodeSimulator(FullNode): def _set_server(self, server: ChiaServer): super()._set_server(server) async def _on_connect(self) -> OutboundMessageGenerator: """ Whenever we connect to another node / wallet, send them our current heads. Also send heads to farmers and challenges to timelords. """ async for msg in super()._on_connect(): yield msg @api_request
if __name__ == "__main__": from tests.block_tools import BlockTools, test_constants from chia.util.default_root import DEFAULT_ROOT_PATH # TODO: mariano: fix this with new consensus bt = BlockTools(root_path=DEFAULT_ROOT_PATH) new_genesis_block = bt.create_genesis_block(test_constants, b"0") print(bytes(new_genesis_block))
async def extra_node(self): b_tools = BlockTools(constants=test_constants_modified) async for _ in setup_full_node(test_constants_modified, "blockchain_test_3.db", 21240, b_tools): yield _
from chia.protocols.timelord_protocol import NewInfusionPointVDF from chia.types.blockchain_format.sized_bytes import bytes32 from chia.types.unfinished_block import UnfinishedBlock from chia.util.block_cache import BlockCache from tests.block_tools import get_signage_point, BlockTools from chia.util.hash import std_hash from chia.util.ints import uint8, uint32, uint64, uint128 from tests.core.fixtures import default_1000_blocks, create_blockchain # noqa: F401 from tests.setup_nodes import test_constants as test_constants_original test_constants = test_constants_original.replace( **{ "DISCRIMINANT_SIZE_BITS": 32, "SUB_SLOT_ITERS_STARTING": 2**12 }) bt = BlockTools(test_constants) @pytest.fixture(scope="session") def event_loop(): loop = asyncio.get_event_loop() yield loop log = logging.getLogger(__name__) @pytest.fixture(scope="function") async def empty_blockchain(): bc1, connection, db_path = await create_blockchain(test_constants) yield bc1
import json import aiohttp import pytest from chia.server.outbound_message import NodeType from chia.server.server import ssl_context_for_server from chia.types.peer_info import PeerInfo from tests.block_tools import BlockTools from chia.util.ints import uint16 from chia.util.ws_message import create_payload from tests.core.node_height import node_height_at_least from tests.setup_nodes import setup_daemon, self_hostname, setup_full_system from tests.simulation.test_simulation import test_constants_modified from tests.time_out_assert import time_out_assert, time_out_assert_custom_interval b_tools = BlockTools(constants=test_constants_modified) b_tools_1 = BlockTools(constants=test_constants_modified) new_config = b_tools._config new_config["daemon_port"] = 55401 b_tools.change_config(new_config) class TestDaemon: @pytest.fixture(scope="function") async def get_daemon(self): async for _ in setup_daemon(btools=b_tools): yield _ @pytest.fixture(scope="function") async def simulation(self): async for _ in setup_full_system(b_tools_1.constants,
async def test_invalid_filter(self, two_nodes): num_blocks = 10 wallet_a = WalletTool() coinbase_puzzlehash = wallet_a.get_new_puzzlehash() wallet_receiver = WalletTool() receiver_puzzlehash = wallet_receiver.get_new_puzzlehash() blocks = bt.get_consecutive_blocks( test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash ) full_node_1, full_node_2, server_1, server_2 = two_nodes for block in blocks: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block) ): pass spent_block = blocks[1] spend_bundle = wallet_a.generate_signed_transaction( 1000, receiver_puzzlehash, spent_block.header.data.coinbase ) assert spend_bundle is not None tx: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction( spend_bundle ) async for _ in full_node_1.respond_transaction(tx): outbound: OutboundMessage = _ # Maybe transaction means that it's accepted in mempool assert outbound.message.function == "new_transaction" sb = full_node_1.mempool_manager.get_spendbundle(spend_bundle.name()) assert sb is spend_bundle last_block = blocks[10] next_spendbundle = await full_node_1.mempool_manager.create_bundle_for_tip( last_block.header ) assert next_spendbundle is not None program = best_solution_program(next_spendbundle) aggsig = next_spendbundle.aggregated_signature dic_h = {11: (program, aggsig)} new_blocks = bt.get_consecutive_blocks( test_constants, 1, blocks, 10, b"", coinbase_puzzlehash, dic_h ) next_block = new_blocks[11] bad_header = HeaderData( next_block.header.data.height, next_block.header.data.prev_header_hash, next_block.header.data.timestamp, bytes32(bytes([3] * 32)), next_block.header.data.proof_of_space_hash, next_block.header.data.weight, next_block.header.data.total_iters, next_block.header.data.additions_root, next_block.header.data.removals_root, next_block.header.data.coinbase, next_block.header.data.coinbase_signature, next_block.header.data.fees_coin, next_block.header.data.aggregated_signature, next_block.header.data.cost, next_block.header.data.extension_data, next_block.header.data.generator_hash, ) bad_block = FullBlock( next_block.proof_of_space, next_block.proof_of_time, Header( bad_header, BlockTools.get_harvester_signature( bad_header, next_block.proof_of_space.plot_pubkey ), ), next_block.transactions_generator, next_block.transactions_filter, ) result, removed, error_code = await full_node_1.blockchain.receive_block( bad_block ) assert result == ReceiveBlockResult.INVALID_BLOCK assert error_code == Err.INVALID_TRANSACTIONS_FILTER_HASH result, removed, error_code = await full_node_1.blockchain.receive_block( next_block ) assert result == ReceiveBlockResult.ADDED_TO_HEAD
import asyncio from secrets import token_bytes from typing import Any, Dict import os import sqlite3 import random import pytest from src.consensus.constants import constants from src.store import FullNodeStore from src.types.full_block import FullBlock from src.types.sized_bytes import bytes32 from src.util.ints import uint32, uint64 from tests.block_tools import BlockTools bt = BlockTools() test_constants: Dict[str, Any] = { "DIFFICULTY_STARTING": 5, "DISCRIMINANT_SIZE_BITS": 16, "BLOCK_TIME_TARGET": 10, "MIN_BLOCK_TIME": 2, "DIFFICULTY_FACTOR": 3, "DIFFICULTY_EPOCH": 12, # The number of blocks per epoch "DIFFICULTY_WARP_FACTOR": 4, # DELAY divides EPOCH in order to warp efficiently. "DIFFICULTY_DELAY": 3, # EPOCH / WARP_FACTOR } test_constants["GENESIS_BLOCK"] = bytes( bt.create_genesis_block(test_constants, bytes([0] * 32), b"0"))
async def test_timestamp(self, initial_blockchain): blocks, b = initial_blockchain # Time too far in the past new_header_data = HeaderData( blocks[9].header.data.height, blocks[9].header.data.prev_header_hash, blocks[9].header.data.timestamp - 1000, blocks[9].header.data.filter_hash, blocks[9].header.data.proof_of_space_hash, blocks[9].header.data.weight, blocks[9].header.data.total_iters, blocks[9].header.data.additions_root, blocks[9].header.data.removals_root, blocks[9].header.data.coinbase, blocks[9].header.data.coinbase_signature, blocks[9].header.data.fees_coin, blocks[9].header.data.aggregated_signature, blocks[9].header.data.cost, blocks[9].header.data.extension_data, blocks[9].header.data.generator_hash, ) block_bad = FullBlock( blocks[9].proof_of_space, blocks[9].proof_of_time, Header( new_header_data, BlockTools.get_harvester_signature( new_header_data, blocks[9].proof_of_space.plot_pubkey), ), blocks[9].transactions_generator, blocks[9].transactions_filter, ) result, removed, error_code = await b.receive_block(block_bad) assert (result) == ReceiveBlockResult.INVALID_BLOCK assert error_code == Err.TIMESTAMP_TOO_FAR_IN_PAST # Time too far in the future new_header_data = HeaderData( blocks[9].header.data.height, blocks[9].header.data.prev_header_hash, uint64(int(time.time() + 3600 * 3)), blocks[9].header.data.filter_hash, blocks[9].header.data.proof_of_space_hash, blocks[9].header.data.weight, blocks[9].header.data.total_iters, blocks[9].header.data.additions_root, blocks[9].header.data.removals_root, blocks[9].header.data.coinbase, blocks[9].header.data.coinbase_signature, blocks[9].header.data.fees_coin, blocks[9].header.data.aggregated_signature, blocks[9].header.data.cost, blocks[9].header.data.extension_data, blocks[9].header.data.generator_hash, ) block_bad = FullBlock( blocks[9].proof_of_space, blocks[9].proof_of_time, Header( new_header_data, BlockTools.get_harvester_signature( new_header_data, blocks[9].proof_of_space.plot_pubkey), ), blocks[9].transactions_generator, blocks[9].transactions_filter, ) result, removed, error_code = await b.receive_block(block_bad) assert (result) == ReceiveBlockResult.INVALID_BLOCK assert error_code == Err.TIMESTAMP_TOO_FAR_IN_FUTURE