chia-blockchain/chia/simulator/full_node_simulator.py

134 lines
5.3 KiB
Python

from typing import List, Optional
from chia.consensus.block_record import BlockRecord
from chia.full_node.full_node_api import FullNodeAPI
from chia.protocols.full_node_protocol import RespondBlock
from chia.simulator.simulator_protocol import FarmNewBlockProtocol, ReorgProtocol
from chia.types.full_block import FullBlock
from chia.util.api_decorators import api_request
from chia.util.ints import uint8
class FullNodeSimulator(FullNodeAPI):
def __init__(self, full_node, block_tools) -> None:
super().__init__(full_node)
self.bt = block_tools
self.full_node = full_node
self.config = full_node.config
self.time_per_block = None
if "simulation" in self.config and self.config["simulation"] is True:
self.use_current_time = True
else:
self.use_current_time = False
async def get_all_full_blocks(self) -> List[FullBlock]:
peak: Optional[BlockRecord] = self.full_node.blockchain.get_peak()
if peak is None:
return []
blocks = []
peak_block = await self.full_node.blockchain.get_full_block(peak.header_hash)
if peak_block is None:
return []
blocks.append(peak_block)
current = peak_block
while True:
prev = await self.full_node.blockchain.get_full_block(current.prev_header_hash)
if prev is not None:
current = prev
blocks.append(prev)
else:
break
blocks.reverse()
return blocks
@api_request
async def farm_new_transaction_block(self, request: FarmNewBlockProtocol):
async with self.full_node.blockchain.lock:
self.log.info("Farming new block!")
current_blocks = await self.get_all_full_blocks()
if len(current_blocks) == 0:
genesis = self.bt.get_consecutive_blocks(uint8(1))[0]
await self.full_node.blockchain.receive_block(genesis)
peak = self.full_node.blockchain.get_peak()
assert peak is not None
curr: BlockRecord = peak
while not curr.is_transaction_block:
curr = self.full_node.blockchain.block_record(curr.prev_hash)
mempool_bundle = await self.full_node.mempool_manager.create_bundle_from_mempool(curr.header_hash)
if mempool_bundle is None:
spend_bundle = None
else:
spend_bundle = mempool_bundle[0]
current_blocks = await self.get_all_full_blocks()
target = request.puzzle_hash
more = self.bt.get_consecutive_blocks(
1,
time_per_block=self.time_per_block,
transaction_data=spend_bundle,
farmer_reward_puzzle_hash=target,
pool_reward_puzzle_hash=target,
block_list_input=current_blocks,
guarantee_transaction_block=True,
current_time=self.use_current_time,
previous_generator=self.full_node.full_node_store.previous_generator,
)
rr = RespondBlock(more[-1])
await self.full_node.respond_block(rr)
@api_request
async def farm_new_block(self, request: FarmNewBlockProtocol):
async with self.full_node.blockchain.lock:
self.log.info("Farming new block!")
current_blocks = await self.get_all_full_blocks()
if len(current_blocks) == 0:
genesis = self.bt.get_consecutive_blocks(uint8(1))[0]
await self.full_node.blockchain.receive_block(genesis)
peak = self.full_node.blockchain.get_peak()
assert peak is not None
curr: BlockRecord = peak
while not curr.is_transaction_block:
curr = self.full_node.blockchain.block_record(curr.prev_hash)
mempool_bundle = await self.full_node.mempool_manager.create_bundle_from_mempool(curr.header_hash)
if mempool_bundle is None:
spend_bundle = None
else:
spend_bundle = mempool_bundle[0]
current_blocks = await self.get_all_full_blocks()
target = request.puzzle_hash
more = self.bt.get_consecutive_blocks(
1,
transaction_data=spend_bundle,
farmer_reward_puzzle_hash=target,
pool_reward_puzzle_hash=target,
block_list_input=current_blocks,
current_time=self.use_current_time,
)
rr: RespondBlock = RespondBlock(more[-1])
await self.full_node.respond_block(rr)
@api_request
async def reorg_from_index_to_new_index(self, request: ReorgProtocol):
new_index = request.new_index
old_index = request.old_index
coinbase_ph = request.puzzle_hash
current_blocks = await self.get_all_full_blocks()
block_count = new_index - old_index
more_blocks = self.bt.get_consecutive_blocks(
block_count,
farmer_reward_puzzle_hash=coinbase_ph,
pool_reward_puzzle_hash=coinbase_ph,
block_list_input=current_blocks[: old_index + 1],
force_overflow=True,
guarantee_transaction_block=True,
seed=32 * b"1",
)
for block in more_blocks:
await self.full_node.respond_block(RespondBlock(block))