Skip to content

Commit

Permalink
get spends for block using transaction generator
Browse files Browse the repository at this point in the history
  • Loading branch information
freddiecoleman committed Feb 26, 2022
1 parent bf4a632 commit c69f96f
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 0 deletions.
61 changes: 61 additions & 0 deletions chia/rpc/full_node_rpc_api.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
from typing import Any, Callable, Dict, List, Optional

from clvm.casts import int_from_bytes
from clvm_rs import COND_CANON_INTS, NO_NEG_DIV

from chia.consensus.block_record import BlockRecord
from chia.consensus.default_constants import DEFAULT_CONSTANTS
from chia.consensus.pos_quality import UI_ACTUAL_SPACE_CONSTANT_FACTOR
from chia.full_node.full_node import FullNode
from chia.full_node.generator import create_generator_args
from chia.full_node.mempool_check_conditions import get_puzzle_and_solution_for_coin
from chia.types.blockchain_format.coin import Coin
from chia.types.blockchain_format.program import Program, SerializedProgram
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.types.coin_record import CoinRecord
Expand Down Expand Up @@ -40,6 +46,7 @@ def get_routes(self) -> Dict[str, Callable]:
"/get_block_record_by_height": self.get_block_record_by_height,
"/get_block_record": self.get_block_record,
"/get_block_records": self.get_block_records,
"/get_block_spends": self.get_block_spends,
"/get_unfinished_block_headers": self.get_unfinished_block_headers,
"/get_network_space": self.get_network_space,
"/get_additions_and_removals": self.get_additions_and_removals,
Expand Down Expand Up @@ -397,6 +404,60 @@ async def get_block_records(self, request: Dict) -> Optional[Dict]:
records.append(record)
return {"block_records": records}

async def get_block_spends(self, request: Dict) -> Optional[Dict]:
if "header_hash" not in request:
raise ValueError("No header_hash in request")
header_hash = bytes32.from_hexstr(request["header_hash"])
full_block: Optional[FullBlock] = await self.service.block_store.get_full_block(header_hash)
if full_block is None:
raise ValueError(f"Block {header_hash.hex()} not found")

ref_list = full_block.transactions_generator_ref_list
tx_info = full_block.transactions_info
generator_program = full_block.transactions_generator
height = full_block.reward_chain_block.height
spends: List[CoinSpend] = []
if tx_info and generator_program:
cost = tx_info.cost
generator_args: List[SerializedProgram] = []
for height in ref_list:
ref_header_hash: Optional[bytes32] = self.service.blockchain.height_to_hash(height)
if ref_header_hash is None:
raise ValueError(f"Block hash {height} not found in chain")
ref_block: Optional[FullBlock] = await self.service.block_store.get_full_block(ref_header_hash)
if ref_block is None:
raise ValueError(f"Block {ref_header_hash} does not exist")
if ref_block.transactions_generator is not None:
generator_args.append(ref_block.transactions_generator)

if not generator_program:
return {"block_spends": spends}
block_generator = BlockGenerator(generator_program, generator_args, [])

if height >= DEFAULT_CONSTANTS.SOFT_FORK_HEIGHT:
# conditions must use integers in canonical encoding (i.e. no redundant
# leading zeros)
# the division operator may not be used with negative operands
flags = COND_CANON_INTS | NO_NEG_DIV
else:
flags = 0

args = create_generator_args(block_generator.generator_refs).first()
_, block_result = block_generator.program.run_with_cost(
min(self.service.constants.MAX_BLOCK_COST_CLVM, cost), flags, args
)

coin_spends = block_result.first()

for spend in coin_spends.as_iter():

parent, puzzle, amount, solution = spend.as_iter()
puzzle_hash = puzzle.get_tree_hash()
coin = Coin(parent.atom, puzzle_hash, int_from_bytes(amount.atom))
spends.append(CoinSpend(coin, puzzle, solution))

return {"block_spends": spends}

async def get_block_record_by_height(self, request: Dict) -> Optional[Dict]:
if "height" not in request:
raise ValueError("No height in request")
Expand Down
7 changes: 7 additions & 0 deletions chia/rpc/full_node_rpc_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,13 @@ async def get_block_records(self, start: int, end: int) -> List:
# TODO: return block records
return response["block_records"]

async def get_block_spends(self, header_hash: bytes32) -> List:
try:
response = await self.fetch("get_block_spends", {"header_hash": header_hash.hex()})
except Exception:
return []
return response["block_spends"]

async def push_tx(self, spend_bundle: SpendBundle):
return await self.fetch("push_tx", {"spend_bundle": spend_bundle.to_json_dict()})

Expand Down
3 changes: 3 additions & 0 deletions tests/core/test_full_node_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ def stop_node_cb():
additions, removals = await client.get_additions_and_removals(blocks[-1].header_hash)
assert len(additions) >= 2 and len(removals) == 0

block_spends = await client.get_block_spends(blocks[-1].header_hash)
assert len(block_spends) >= 2

wallet = WalletTool(full_node_api_1.full_node.constants)
wallet_receiver = WalletTool(full_node_api_1.full_node.constants, AugSchemeMPL.key_gen(std_hash(b"123123")))
ph = wallet.get_new_puzzlehash()
Expand Down

0 comments on commit c69f96f

Please sign in to comment.