Skip to content

Commit

Permalink
Merge pull request #866 from Chia-Network/execution-time
Browse files Browse the repository at this point in the history
extend `SpendBundleConditions` with the cost broken out
  • Loading branch information
arvidn authored Jan 13, 2025
2 parents 4444a22 + 5d8cb1f commit 10bc9f2
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 11 deletions.
2 changes: 2 additions & 0 deletions crates/chia-consensus/fuzz/fuzz_targets/run-generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ fuzz_target!(|data: &[u8]| {
}
(Ok(a), Ok(b)) => {
assert!(a.cost >= b.cost);
assert!(a.execution_cost > b.execution_cost);
assert_eq!(a.condition_cost, b.condition_cost);
assert_eq!(a.reserve_fee, b.reserve_fee);
assert_eq!(a.removal_amount, b.removal_amount);
assert_eq!(a.addition_amount, b.addition_amount);
Expand Down
9 changes: 9 additions & 0 deletions crates/chia-consensus/src/gen/conditions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,12 @@ pub struct SpendBundleConditions {
// the total cost)
pub cost: u64,

// the cost of executing the Chialisp
pub execution_cost: u64,

// the cost of the conditions
pub condition_cost: u64,

// the sum of all values of all spent coins
pub removal_amount: u128,

Expand Down Expand Up @@ -921,6 +927,7 @@ pub fn parse_conditions<V: SpendVisitor>(
return Err(ValidationErr(c, ErrorCode::CostExceeded));
}
*max_cost -= CREATE_COIN_COST;
ret.condition_cost += CREATE_COIN_COST;
}
AGG_SIG_UNSAFE
| AGG_SIG_ME
Expand All @@ -934,6 +941,7 @@ pub fn parse_conditions<V: SpendVisitor>(
return Err(ValidationErr(c, ErrorCode::CostExceeded));
}
*max_cost -= AGG_SIG_COST;
ret.condition_cost += AGG_SIG_COST;
}
_ => (),
}
Expand Down Expand Up @@ -1212,6 +1220,7 @@ pub fn parse_conditions<V: SpendVisitor>(
return Err(ValidationErr(c, ErrorCode::CostExceeded));
}
*max_cost -= cost;
ret.condition_cost += cost;
}
Condition::SendMessage(src_mode, dst, msg) => {
decrement(&mut announce_countdown, msg)?;
Expand Down
4 changes: 4 additions & 0 deletions crates/chia-consensus/src/gen/owned_conditions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ pub struct OwnedSpendBundleConditions {
// set if the aggregate signature of the block/spend bundle was
// successfully validated
pub validated_signature: bool,
pub execution_cost: u64,
pub condition_cost: u64,
}

impl OwnedSpendConditions {
Expand Down Expand Up @@ -144,6 +146,8 @@ impl OwnedSpendBundleConditions {
removal_amount: sb.removal_amount,
addition_amount: sb.addition_amount,
validated_signature: sb.validated_signature,
execution_cost: sb.execution_cost,
condition_cost: sb.condition_cost,
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion crates/chia-consensus/src/gen/run_block_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ where
constants,
)?;
result.cost += max_cost - cost_left;
result.execution_cost = clvm_cost;
Ok(result)
}

Expand Down Expand Up @@ -189,13 +190,16 @@ where
let Reduction(clvm_cost, mut all_spends) = run_program(a, &dialect, program, args, cost_left)?;

subtract_cost(a, &mut cost_left, clvm_cost)?;

let mut ret = SpendBundleConditions::default();

all_spends = first(a, all_spends)?;
ret.execution_cost += clvm_cost;

// at this point all_spends is a list of:
// (parent-coin-id puzzle-reveal amount solution . extra)
// where extra may be nil, or additional extension data

let mut ret = SpendBundleConditions::default();
let mut state = ParseState::default();
let mut cache = HashMap::<NodePtr, TreeHash>::new();

Expand All @@ -209,6 +213,7 @@ where
run_program(a, &dialect, puzzle, solution, cost_left)?;

subtract_cost(a, &mut cost_left, clvm_cost)?;
ret.execution_cost += clvm_cost;

let buf = tree_hash_cached(a, puzzle, &backrefs, &mut cache);
let puzzle_hash = a.new_atom(&buf)?;
Expand Down
16 changes: 15 additions & 1 deletion crates/chia-consensus/src/spendbundle_conditions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ pub fn run_spendbundle(
let amount = a.new_number(coin_spend.coin.amount.into())?;
let Reduction(clvm_cost, conditions) = run_program(a, &dialect, puz, sol, cost_left)?;

ret.execution_cost += clvm_cost;
subtract_cost(a, &mut cost_left, clvm_cost)?;

let buf = tree_hash(a, puz);
Expand Down Expand Up @@ -169,6 +170,12 @@ mod tests {
conditions.cost,
block_conds.cost - QUOTE_EXECUTION_COST - QUOTE_BYTES_COST
);

assert_eq!(
conditions.execution_cost,
block_conds.execution_cost - QUOTE_EXECUTION_COST
);
assert_eq!(conditions.condition_cost, block_conds.condition_cost);
}

#[rstest]
Expand Down Expand Up @@ -382,10 +389,17 @@ mod tests {
- QUOTE_BYTES;
let bundle_byte_cost =
generator_length_without_quote as u64 * TEST_CONSTANTS.cost_per_byte;
println!("block_cost: {block_cost} bytes: {block_byte_cost}");
println!(" block_cost: {block_cost} bytes: {block_byte_cost}");
println!("bundle_cost: {} bytes: {bundle_byte_cost}", conditions.cost);
println!("execution_cost: {}", conditions.execution_cost);
println!("condition_cost: {}", conditions.condition_cost);
assert!(conditions.cost - bundle_byte_cost <= block_cost - block_byte_cost);
assert!(conditions.cost > 0);
assert!(conditions.execution_cost > 0);
assert_eq!(
conditions.cost,
conditions.condition_cost + conditions.execution_cost + bundle_byte_cost
);
// update the cost we print here, just to be compatible with
// the test cases we have. We've already ensured the cost is
// lower
Expand Down
19 changes: 17 additions & 2 deletions tests/test_run_block_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,16 @@ def test_run_block_generator_cost() -> None:
# longer pay the cost of the generator ROM
hard_fork_consensus_cost = 596498808

# the generator always produce the same set of conditions, and their cost
# is the same regardless of pre- or post- hard fork.
condition_cost = 122400000

generator = bytes.fromhex(
open("generator-tests/block-834768.txt", "r").read().split("\n")[0]
)

byte_cost = len(generator) * 12000

err, conds = run_block_generator(
generator,
[],
Expand All @@ -29,6 +36,9 @@ def test_run_block_generator_cost() -> None:
)
assert err is None
assert conds is not None
assert conds.cost == original_consensus_cost
assert conds.execution_cost + condition_cost + byte_cost == original_consensus_cost
assert conds.condition_cost == condition_cost

err2, conds2 = run_block_generator2(
generator,
Expand All @@ -41,6 +51,11 @@ def test_run_block_generator_cost() -> None:
)
assert err2 is None
assert conds2 is not None
assert conds2.cost == hard_fork_consensus_cost
assert conds2.condition_cost == condition_cost
assert (
conds2.execution_cost + condition_cost + byte_cost == hard_fork_consensus_cost
)

output1 = print_spend_bundle_conditions(conds)
output2 = print_spend_bundle_conditions(conds2)
Expand Down Expand Up @@ -81,7 +96,7 @@ def test_run_block_generator_cost() -> None:
err, conds = run_block_generator(
generator,
[],
len(generator) * 12000 - 1,
byte_cost - 1,
DONT_VALIDATE_SIGNATURE,
G2Element(),
None,
Expand All @@ -95,7 +110,7 @@ def test_run_block_generator_cost() -> None:
err, conds = run_block_generator2(
generator,
[],
len(generator) * 12000 - 1,
byte_cost - 1,
DONT_VALIDATE_SIGNATURE,
G2Element(),
None,
Expand Down
74 changes: 69 additions & 5 deletions tests/test_streamable.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,34 @@ def test_hash_spend() -> None:
def test_hash_spend_bundle_conditions() -> None:

a1 = SpendBundleConditions(
[], 1000, 1337, 42, None, None, [(pk, b"msg")], 12345678, 123, 456, False
[],
1000,
1337,
42,
None,
None,
[(pk, b"msg")],
12345678,
123,
456,
False,
4321,
8765,
)
a2 = SpendBundleConditions(
[], 1001, 1337, 42, None, None, [(pk, b"msg")], 12345678, 123, 456, False
[],
1001,
1337,
42,
None,
None,
[(pk, b"msg")],
12345678,
123,
456,
False,
4321,
8765,
)
b = hash(a1)
c = hash(a2)
Expand Down Expand Up @@ -391,7 +415,19 @@ def test_missing_field() -> None:
def test_json_spend_bundle_conditions() -> None:

a = SpendBundleConditions(
[], 1000, 1337, 42, None, None, [(pk, b"msg")], 12345678, 123, 456, False
[],
1000,
1337,
42,
None,
None,
[(pk, b"msg")],
12345678,
123,
456,
False,
4321,
8765,
)

assert a.to_json_dict() == {
Expand All @@ -406,13 +442,27 @@ def test_json_spend_bundle_conditions() -> None:
"removal_amount": 123,
"addition_amount": 456,
"validated_signature": False,
"execution_cost": 4321,
"condition_cost": 8765,
}


def test_from_json_spend_bundle_conditions() -> None:

a = SpendBundleConditions(
[], 1000, 1337, 42, None, None, [(pk, b"msg")], 12345678, 123, 456, False
[],
1000,
1337,
42,
None,
None,
[(pk, b"msg")],
12345678,
123,
456,
False,
4321,
8765,
)
b = SpendBundleConditions.from_json_dict(
{
Expand All @@ -427,6 +477,8 @@ def test_from_json_spend_bundle_conditions() -> None:
"removal_amount": 123,
"addition_amount": 456,
"validated_signature": False,
"execution_cost": 4321,
"condition_cost": 8765,
}
)
assert a == b
Expand Down Expand Up @@ -468,7 +520,19 @@ def test_copy_spend() -> None:
def test_copy_spend_bundle_conditions() -> None:

a = SpendBundleConditions(
[], 1000, 1337, 42, None, None, [(pk, b"msg")], 12345678, 123, 456, False
[],
1000,
1337,
42,
None,
None,
[(pk, b"msg")],
12345678,
123,
456,
False,
4321,
8765,
)
b = copy.copy(a)

Expand Down
2 changes: 2 additions & 0 deletions wheel/generate_type_stubs.py
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,8 @@ def __init__(
"removal_amount: int",
"addition_amount: int",
"validated_signature: bool",
"execution_cost: int",
"condition_cost: int",
],
)

Expand Down
10 changes: 8 additions & 2 deletions wheel/python/chia_rs/chia_rs.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,8 @@ class SpendBundleConditions:
removal_amount: int
addition_amount: int
validated_signature: bool
execution_cost: int
condition_cost: int
def __init__(
self,
spends: Sequence[SpendConditions],
Expand All @@ -362,7 +364,9 @@ class SpendBundleConditions:
cost: int,
removal_amount: int,
addition_amount: int,
validated_signature: bool
validated_signature: bool,
execution_cost: int,
condition_cost: int
) -> None: ...
def __hash__(self) -> int: ...
def __repr__(self) -> str: ...
Expand Down Expand Up @@ -391,7 +395,9 @@ class SpendBundleConditions:
cost: Union[ int, _Unspec] = _Unspec(),
removal_amount: Union[ int, _Unspec] = _Unspec(),
addition_amount: Union[ int, _Unspec] = _Unspec(),
validated_signature: Union[ bool, _Unspec] = _Unspec()) -> SpendBundleConditions: ...
validated_signature: Union[ bool, _Unspec] = _Unspec(),
execution_cost: Union[ int, _Unspec] = _Unspec(),
condition_cost: Union[ int, _Unspec] = _Unspec()) -> SpendBundleConditions: ...

@final
class BlockRecord:
Expand Down

0 comments on commit 10bc9f2

Please sign in to comment.