Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New RPC block_spends - Get spends for block using transaction generator #10446

Merged
merged 24 commits into from
Jun 24, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
c69f96f
get spends for block using transaction generator
freddiecoleman Feb 26, 2022
b7f961e
type annotations and use existing function
freddiecoleman Feb 26, 2022
914aa58
return None on exception
freddiecoleman Feb 26, 2022
402c9a1
parse to CoinSpend
freddiecoleman Feb 26, 2022
5dd28b8
specify return type of get_block_spends in rpc client
freddiecoleman Feb 26, 2022
9b1fd78
see what can be asserted
freddiecoleman Feb 26, 2022
d7b181f
test fix
freddiecoleman Feb 27, 2022
faad4d4
flags not necessary as we don't validate
freddiecoleman Mar 13, 2022
ae579aa
simplifying as cost is not required as we are not validating
freddiecoleman Mar 13, 2022
5e857ff
improve test to cover transaction generator ref_list
freddiecoleman Mar 13, 2022
58baa04
Merge branch 'main' of github.com:freddiecoleman/chia-blockchain into…
freddiecoleman Mar 13, 2022
74ca788
simplify test
freddiecoleman Mar 13, 2022
d7f2079
Merge branch 'main' of github.com:freddiecoleman/chia-blockchain into…
freddiecoleman Mar 18, 2022
4a2909a
remove unused import
freddiecoleman Mar 18, 2022
57666c5
Merge branch 'main' of github.com:freddiecoleman/chia-blockchain into…
freddiecoleman Apr 4, 2022
b7b4f7e
Merge branch 'main' of github.com:freddiecoleman/chia-blockchain into…
freddiecoleman May 14, 2022
6595a95
slight change and cleanup
jack60612 Jun 16, 2022
5dfbe7f
Merge branch 'main' into jn.get_block_spends_changes
jack60612 Jun 16, 2022
a3a2483
lint cleanup
jack60612 Jun 16, 2022
24f6328
clean up
jack60612 Jun 17, 2022
89bb9e4
wait until transaction is in mempool
jack60612 Jun 24, 2022
4951131
Merge branch 'main' into jn.get_block_spends_changes
jack60612 Jun 24, 2022
27d8061
fix lint
jack60612 Jun 24, 2022
d53f02c
Merge pull request #1 from Chia-Network/jn.get_block_spends_changes
freddiecoleman Jun 24, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
freddiecoleman marked this conversation as resolved.
Show resolved Hide resolved
tx_info = full_block.transactions_info
freddiecoleman marked this conversation as resolved.
Show resolved Hide resolved
generator_program = full_block.transactions_generator
height = full_block.reward_chain_block.height
spends: List[CoinSpend] = []
if tx_info and generator_program:
freddiecoleman marked this conversation as resolved.
Show resolved Hide resolved
cost = tx_info.cost
generator_args: List[SerializedProgram] = []
for height in ref_list:
freddiecoleman marked this conversation as resolved.
Show resolved Hide resolved
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
freddiecoleman marked this conversation as resolved.
Show resolved Hide resolved

args = create_generator_args(block_generator.generator_refs).first()
_, block_result = block_generator.program.run_with_cost(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

program is a SerializedProgram, right?
Getting the generator arguments right here is non trivial. Are you confident the test covers this properly?

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:
freddiecoleman marked this conversation as resolved.
Show resolved Hide resolved
try:
response = await self.fetch("get_block_spends", {"header_hash": header_hash.hex()})
except Exception:
freddiecoleman marked this conversation as resolved.
Show resolved Hide resolved
return []
return response["block_spends"]
freddiecoleman marked this conversation as resolved.
Show resolved Hide resolved

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)
freddiecoleman marked this conversation as resolved.
Show resolved Hide resolved
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