remove redundant cost field in NPCResults (#17167)

This commit is contained in:
Arvid Norberg 2024-01-02 18:45:23 +01:00 committed by GitHub
parent cd78dbafdd
commit 57a59abde0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 47 additions and 33 deletions

View File

@ -71,11 +71,12 @@ class CostLogger:
height=DEFAULT_CONSTANTS.HARD_FORK_HEIGHT, height=DEFAULT_CONSTANTS.HARD_FORK_HEIGHT,
constants=DEFAULT_CONSTANTS, constants=DEFAULT_CONSTANTS,
) )
self.cost_dict[descriptor] = npc_result.cost cost = uint64(0 if npc_result.conds is None else npc_result.conds.cost)
self.cost_dict[descriptor] = cost
cost_to_subtract: int = 0 cost_to_subtract: int = 0
for cs in spend_bundle.coin_spends: for cs in spend_bundle.coin_spends:
cost_to_subtract += len(bytes(cs.puzzle_reveal)) * DEFAULT_CONSTANTS.COST_PER_BYTE cost_to_subtract += len(bytes(cs.puzzle_reveal)) * DEFAULT_CONSTANTS.COST_PER_BYTE
self.cost_dict_no_puzs[descriptor] = npc_result.cost - cost_to_subtract self.cost_dict_no_puzs[descriptor] = cost - cost_to_subtract
return spend_bundle return spend_bundle
def log_cost_statistics(self) -> str: def log_cost_statistics(self) -> str:

View File

@ -294,7 +294,7 @@ async def validate_block_body(
# Get List of names removed, puzzles hashes for removed coins and conditions created # Get List of names removed, puzzles hashes for removed coins and conditions created
assert npc_result is not None assert npc_result is not None
cost = npc_result.cost cost = uint64(0 if npc_result.conds is None else npc_result.conds.cost)
# 7. Check that cost <= MAX_BLOCK_COST_CLVM # 7. Check that cost <= MAX_BLOCK_COST_CLVM
log.debug( log.debug(

View File

@ -39,7 +39,7 @@ def compute_block_cost(generator: BlockGenerator, constants: ConsensusConstants,
result: NPCResult = get_name_puzzle_conditions( result: NPCResult = get_name_puzzle_conditions(
generator, constants.MAX_BLOCK_COST_CLVM, mempool_mode=True, height=height, constants=constants generator, constants.MAX_BLOCK_COST_CLVM, mempool_mode=True, height=height, constants=constants
) )
return result.cost return uint64(0 if result.conds is None else result.conds.cost)
def compute_block_fee(additions: Sequence[Coin], removals: Sequence[Coin]) -> uint64: def compute_block_fee(additions: Sequence[Coin], removals: Sequence[Coin]) -> uint64:

View File

@ -4,7 +4,7 @@ from dataclasses import dataclass
from typing import Optional from typing import Optional
from chia.types.spend_bundle_conditions import SpendBundleConditions from chia.types.spend_bundle_conditions import SpendBundleConditions
from chia.util.ints import uint16, uint64 from chia.util.ints import uint16
from chia.util.streamable import Streamable, streamable from chia.util.streamable import Streamable, streamable
@ -13,5 +13,3 @@ from chia.util.streamable import Streamable, streamable
class NPCResult(Streamable): class NPCResult(Streamable):
error: Optional[uint16] error: Optional[uint16]
conds: Optional[SpendBundleConditions] conds: Optional[SpendBundleConditions]
cost: uint64 # The total cost of the block, including CLVM cost, cost of
# conditions and cost of bytes

View File

@ -406,6 +406,6 @@ def _run_generator(
) )
return bytes(npc_result) return bytes(npc_result)
except ValidationError as e: except ValidationError as e:
return bytes(NPCResult(uint16(e.code.value), None, uint64(0))) return bytes(NPCResult(uint16(e.code.value), None))
except Exception: except Exception:
return bytes(NPCResult(uint16(Err.UNKNOWN.value), None, uint64(0))) return bytes(NPCResult(uint16(Err.UNKNOWN.value), None))

View File

@ -402,10 +402,11 @@ class Mempool:
if not item_inclusion_filter(name): if not item_inclusion_filter(name):
continue continue
try: try:
cost = uint64(0 if item.npc_result.conds is None else item.npc_result.conds.cost)
unique_coin_spends, cost_saving, unique_additions = eligible_coin_spends.get_deduplication_info( unique_coin_spends, cost_saving, unique_additions = eligible_coin_spends.get_deduplication_info(
bundle_coin_spends=item.bundle_coin_spends, max_cost=item.npc_result.cost bundle_coin_spends=item.bundle_coin_spends, max_cost=cost
) )
item_cost = item.npc_result.cost - cost_saving item_cost = cost - cost_saving
log.info("Cumulative cost: %d, fee per cost: %0.4f", cost_sum, fee / item_cost) log.info("Cumulative cost: %d, fee per cost: %0.4f", cost_sum, fee / item_cost)
if ( if (
item_cost + cost_sum > self.mempool_info.max_block_clvm_cost item_cost + cost_sum > self.mempool_info.max_block_clvm_cost

View File

@ -93,13 +93,13 @@ def get_name_puzzle_conditions(
err, result = run_block(bytes(generator.program), block_args, max_cost, flags) err, result = run_block(bytes(generator.program), block_args, max_cost, flags)
assert (err is None) != (result is None) assert (err is None) != (result is None)
if err is not None: if err is not None:
return NPCResult(uint16(err), None, uint64(0)) return NPCResult(uint16(err), None)
else: else:
assert result is not None assert result is not None
return NPCResult(None, result, uint64(result.cost)) return NPCResult(None, result)
except BaseException: except BaseException:
log.exception("get_name_puzzle_condition failed") log.exception("get_name_puzzle_condition failed")
return NPCResult(uint16(Err.GENERATOR_RUNTIME_ERROR.value), None, uint64(0)) return NPCResult(uint16(Err.GENERATOR_RUNTIME_ERROR.value), None)
def get_puzzle_and_solution_for_coin( def get_puzzle_and_solution_for_coin(

View File

@ -403,7 +403,7 @@ class MempoolManager:
if npc_result.error is not None: if npc_result.error is not None:
return Err(npc_result.error), None, [] return Err(npc_result.error), None, []
cost = npc_result.cost cost = uint64(0 if npc_result.conds is None else npc_result.conds.cost)
log.debug(f"Cost: {cost}") log.debug(f"Cost: {cost}")
assert npc_result.conds is not None assert npc_result.conds is not None

View File

@ -873,7 +873,7 @@ class FullNodeRpcApi:
) )
if npc_result.error is not None: if npc_result.error is not None:
raise RuntimeError(f"Spend Bundle failed validation: {npc_result.error}") raise RuntimeError(f"Spend Bundle failed validation: {npc_result.error}")
cost = npc_result.cost cost = uint64(0 if npc_result.conds is None else npc_result.conds.cost)
elif "cost" in request: elif "cost" in request:
cost = request["cost"] cost = request["cost"]
else: else:

View File

@ -57,7 +57,7 @@ class MempoolItem:
@property @property
def cost(self) -> uint64: def cost(self) -> uint64:
return self.npc_result.cost return uint64(0 if self.npc_result.conds is None else self.npc_result.conds.cost)
@property @property
def additions(self) -> List[Coin]: def additions(self) -> List[Coin]:

View File

@ -7,6 +7,7 @@ from chia.full_node.mempool_check_conditions import get_name_puzzle_conditions
from chia.types.blockchain_format.program import INFINITE_COST from chia.types.blockchain_format.program import INFINITE_COST
from chia.types.generator_types import BlockGenerator from chia.types.generator_types import BlockGenerator
from chia.types.spend_bundle import SpendBundle from chia.types.spend_bundle import SpendBundle
from chia.util.ints import uint64
def cost_of_spend_bundle(spend_bundle: SpendBundle) -> int: def cost_of_spend_bundle(spend_bundle: SpendBundle) -> int:
@ -19,4 +20,4 @@ def cost_of_spend_bundle(spend_bundle: SpendBundle) -> int:
height=DEFAULT_CONSTANTS.HARD_FORK_HEIGHT, height=DEFAULT_CONSTANTS.HARD_FORK_HEIGHT,
constants=DEFAULT_CONSTANTS, constants=DEFAULT_CONSTANTS,
) )
return npc_result.cost return uint64(0 if npc_result.conds is None else npc_result.conds.cost)

View File

@ -800,7 +800,9 @@ class TestFullNodeProtocol:
assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash) is not None assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash) is not None
result = full_node_1.full_node.full_node_store.get_unfinished_block_result(unf.partial_hash) result = full_node_1.full_node.full_node_store.get_unfinished_block_result(unf.partial_hash)
assert result is not None assert result is not None
assert result.npc_result is not None and result.npc_result.cost > 0 assert result.npc_result is not None
assert result.npc_result.conds is not None
assert result.npc_result.conds.cost > 0
assert not full_node_1.full_node.blockchain.contains_block(block.header_hash) assert not full_node_1.full_node.blockchain.contains_block(block.header_hash)
assert block.transactions_generator is not None assert block.transactions_generator is not None

View File

@ -100,7 +100,7 @@ def make_item(idx: int, cost: uint64 = uint64(80), assert_height=100) -> Mempool
return MempoolItem( return MempoolItem(
SpendBundle([], G2Element()), SpendBundle([], G2Element()),
uint64(0), uint64(0),
NPCResult(None, SpendBundleConditions([], 0, 0, 0, None, None, [], cost, 0, 0), cost), NPCResult(None, SpendBundleConditions([], 0, 0, 0, None, None, [], cost, 0, 0)),
spend_bundle_name, spend_bundle_name,
uint32(0), uint32(0),
assert_height, assert_height,
@ -2134,7 +2134,8 @@ class TestGeneratorConditions:
height=softfork_height, height=softfork_height,
) )
assert npc_result.error is None assert npc_result.error is None
assert npc_result.cost == generator_base_cost + 95 * COST_PER_BYTE + ConditionCost.CREATE_COIN.value assert npc_result.conds is not None
assert npc_result.conds.cost == generator_base_cost + 95 * COST_PER_BYTE + ConditionCost.CREATE_COIN.value
assert len(npc_result.conds.spends) == 1 assert len(npc_result.conds.spends) == 1
assert len(npc_result.conds.spends[0].create_coin) == 1 assert len(npc_result.conds.spends[0].create_coin) == 1
@ -2186,7 +2187,8 @@ class TestGeneratorConditions:
height=softfork_height, height=softfork_height,
) )
assert npc_result.error is None assert npc_result.error is None
assert npc_result.cost == generator_base_cost + 117 * COST_PER_BYTE + expected_cost assert npc_result.conds is not None
assert npc_result.conds.cost == generator_base_cost + 117 * COST_PER_BYTE + expected_cost
assert len(npc_result.conds.spends) == 1 assert len(npc_result.conds.spends) == 1
# if we subtract one from max cost, this should fail # if we subtract one from max cost, this should fail

View File

@ -698,7 +698,7 @@ def mk_item(
# can_replace() # can_replace()
spends = [make_spend(c, SerializedProgram.to(None), SerializedProgram.to(None)) for c in coins] spends = [make_spend(c, SerializedProgram.to(None), SerializedProgram.to(None)) for c in coins]
spend_bundle = SpendBundle(spends, G2Element()) spend_bundle = SpendBundle(spends, G2Element())
npc_result = NPCResult(None, make_test_conds(cost=cost, spend_ids=[c.name() for c in coins]), uint64(cost)) npc_result = NPCResult(None, make_test_conds(cost=cost, spend_ids=[c.name() for c in coins]))
return MempoolItem( return MempoolItem(
spend_bundle, spend_bundle,
uint64(fee), uint64(fee),
@ -1258,9 +1258,10 @@ def test_dedup_info_nothing_to_do() -> None:
] ]
sb = spend_bundle_from_conditions(conditions, TEST_COIN) sb = spend_bundle_from_conditions(conditions, TEST_COIN)
mempool_item = mempool_item_from_spendbundle(sb) mempool_item = mempool_item_from_spendbundle(sb)
assert mempool_item.npc_result.conds is not None
eligible_coin_spends = EligibleCoinSpends() eligible_coin_spends = EligibleCoinSpends()
unique_coin_spends, cost_saving, unique_additions = eligible_coin_spends.get_deduplication_info( unique_coin_spends, cost_saving, unique_additions = eligible_coin_spends.get_deduplication_info(
bundle_coin_spends=mempool_item.bundle_coin_spends, max_cost=mempool_item.npc_result.cost bundle_coin_spends=mempool_item.bundle_coin_spends, max_cost=mempool_item.npc_result.conds.cost
) )
assert unique_coin_spends == sb.coin_spends assert unique_coin_spends == sb.coin_spends
assert cost_saving == 0 assert cost_saving == 0
@ -1276,10 +1277,11 @@ def test_dedup_info_eligible_1st_time() -> None:
] ]
sb = spend_bundle_from_conditions(conditions, TEST_COIN) sb = spend_bundle_from_conditions(conditions, TEST_COIN)
mempool_item = mempool_item_from_spendbundle(sb) mempool_item = mempool_item_from_spendbundle(sb)
assert mempool_item.npc_result.conds is not None
eligible_coin_spends = EligibleCoinSpends() eligible_coin_spends = EligibleCoinSpends()
solution = SerializedProgram.to(conditions) solution = SerializedProgram.to(conditions)
unique_coin_spends, cost_saving, unique_additions = eligible_coin_spends.get_deduplication_info( unique_coin_spends, cost_saving, unique_additions = eligible_coin_spends.get_deduplication_info(
bundle_coin_spends=mempool_item.bundle_coin_spends, max_cost=mempool_item.npc_result.cost bundle_coin_spends=mempool_item.bundle_coin_spends, max_cost=mempool_item.npc_result.conds.cost
) )
assert unique_coin_spends == sb.coin_spends assert unique_coin_spends == sb.coin_spends
assert cost_saving == 0 assert cost_saving == 0
@ -1301,9 +1303,10 @@ def test_dedup_info_eligible_but_different_solution() -> None:
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 2]] conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 2]]
sb = spend_bundle_from_conditions(conditions, TEST_COIN) sb = spend_bundle_from_conditions(conditions, TEST_COIN)
mempool_item = mempool_item_from_spendbundle(sb) mempool_item = mempool_item_from_spendbundle(sb)
assert mempool_item.npc_result.conds is not None
with pytest.raises(ValueError, match="Solution is different from what we're deduplicating on"): with pytest.raises(ValueError, match="Solution is different from what we're deduplicating on"):
eligible_coin_spends.get_deduplication_info( eligible_coin_spends.get_deduplication_info(
bundle_coin_spends=mempool_item.bundle_coin_spends, max_cost=mempool_item.npc_result.cost bundle_coin_spends=mempool_item.bundle_coin_spends, max_cost=mempool_item.npc_result.conds.cost
) )
@ -1321,8 +1324,9 @@ def test_dedup_info_eligible_2nd_time_and_another_1st_time() -> None:
sb2 = spend_bundle_from_conditions(second_conditions, TEST_COIN2) sb2 = spend_bundle_from_conditions(second_conditions, TEST_COIN2)
sb = SpendBundle.aggregate([sb1, sb2]) sb = SpendBundle.aggregate([sb1, sb2])
mempool_item = mempool_item_from_spendbundle(sb) mempool_item = mempool_item_from_spendbundle(sb)
assert mempool_item.npc_result.conds is not None
unique_coin_spends, cost_saving, unique_additions = eligible_coin_spends.get_deduplication_info( unique_coin_spends, cost_saving, unique_additions = eligible_coin_spends.get_deduplication_info(
bundle_coin_spends=mempool_item.bundle_coin_spends, max_cost=mempool_item.npc_result.cost bundle_coin_spends=mempool_item.bundle_coin_spends, max_cost=mempool_item.npc_result.conds.cost
) )
# Only the eligible one that we encountered more than once gets deduplicated # Only the eligible one that we encountered more than once gets deduplicated
assert unique_coin_spends == sb2.coin_spends assert unique_coin_spends == sb2.coin_spends
@ -1365,8 +1369,9 @@ def test_dedup_info_eligible_3rd_time_another_2nd_time_and_one_non_eligible() ->
sb3 = spend_bundle_from_conditions(sb3_conditions, TEST_COIN3) sb3 = spend_bundle_from_conditions(sb3_conditions, TEST_COIN3)
sb = SpendBundle.aggregate([sb1, sb2, sb3]) sb = SpendBundle.aggregate([sb1, sb2, sb3])
mempool_item = mempool_item_from_spendbundle(sb) mempool_item = mempool_item_from_spendbundle(sb)
assert mempool_item.npc_result.conds is not None
unique_coin_spends, cost_saving, unique_additions = eligible_coin_spends.get_deduplication_info( unique_coin_spends, cost_saving, unique_additions = eligible_coin_spends.get_deduplication_info(
bundle_coin_spends=mempool_item.bundle_coin_spends, max_cost=mempool_item.npc_result.cost bundle_coin_spends=mempool_item.bundle_coin_spends, max_cost=mempool_item.npc_result.conds.cost
) )
assert unique_coin_spends == sb3.coin_spends assert unique_coin_spends == sb3.coin_spends
saved_cost2 = uint64(1800044) saved_cost2 = uint64(1800044)

View File

@ -105,7 +105,7 @@ async def test_basics(softfork_height: int, bt: BlockTools) -> None:
# Create condition + agg_sig_condition + length + cpu_cost # Create condition + agg_sig_condition + length + cpu_cost
assert ( assert (
npc_result.cost npc_result.conds.cost
== ConditionCost.CREATE_COIN.value == ConditionCost.CREATE_COIN.value
+ ConditionCost.AGG_SIG.value + ConditionCost.AGG_SIG.value
+ len(bytes(program.program)) * bt.constants.COST_PER_BYTE + len(bytes(program.program)) * bt.constants.COST_PER_BYTE
@ -248,7 +248,7 @@ async def test_clvm_max_cost(softfork_height: int) -> None:
) )
assert npc_result.error is not None assert npc_result.error is not None
assert npc_result.cost == 0 assert npc_result.conds is None
# raise the max cost to make sure this passes # raise the max cost to make sure this passes
# ensure we pass if the program does not exceeds the cost # ensure we pass if the program does not exceeds the cost
@ -257,7 +257,8 @@ async def test_clvm_max_cost(softfork_height: int) -> None:
) )
assert npc_result.error is None assert npc_result.error is None
assert npc_result.cost > 10000000 assert npc_result.conds is not None
assert npc_result.conds.cost > 10000000
@pytest.mark.anyio @pytest.mark.anyio

View File

@ -47,7 +47,7 @@ def make_mempoolitem() -> MempoolItem:
mempool_item = MempoolItem( mempool_item = MempoolItem(
spend_bundle, spend_bundle,
fee, fee,
NPCResult(None, conds, cost), NPCResult(None, conds),
spend_bundle.name(), spend_bundle.name(),
uint32(block_height), uint32(block_height),
) )

View File

@ -133,7 +133,10 @@ class TestROM:
else: else:
cost = EXPECTED_COST1 cost = EXPECTED_COST1
assert npc_result.error is None assert npc_result.error is None
assert npc_result.cost == cost + ConditionCost.CREATE_COIN.value + (len(bytes(gen.program)) * COST_PER_BYTE) assert npc_result.conds is not None
assert npc_result.conds.cost == cost + ConditionCost.CREATE_COIN.value + (
len(bytes(gen.program)) * COST_PER_BYTE
)
assert npc_result.conds is not None assert npc_result.conds is not None
spend = Spend( spend = Spend(