Skip to content

Commit

Permalink
use real keys and signatures in mempool tests
Browse files Browse the repository at this point in the history
  • Loading branch information
arvidn committed May 20, 2024
1 parent f558a90 commit bf6aa50
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 36 deletions.
4 changes: 2 additions & 2 deletions chia/_tests/core/mempool/test_mempool.py
Original file line number Diff line number Diff line change
Expand Up @@ -2161,7 +2161,7 @@ def test_create_coin_cost(self, softfork_height):
],
)
def test_agg_sig_cost(self, condition, softfork_height):
pubkey = "0x" + bytes(G1Element()).hex()
pubkey = "0x" + bytes(G1Element.generator()).hex()

if softfork_height >= test_constants.HARD_FORK_FIX_HEIGHT:
generator_base_cost = 40
Expand Down Expand Up @@ -2219,7 +2219,7 @@ def test_agg_sig_cost(self, condition, softfork_height):
@pytest.mark.parametrize("extra_arg", [' "baz"', ""])
@pytest.mark.parametrize("mempool", [True, False])
def test_agg_sig_extra_arg(self, condition, extra_arg, mempool, softfork_height):
pubkey = "0x" + bytes(G1Element()).hex()
pubkey = "0x" + bytes(G1Element.generator()).hex()

new_condition = condition in [
ConditionOpcode.AGG_SIG_PARENT,
Expand Down
73 changes: 52 additions & 21 deletions chia/_tests/core/mempool/test_mempool_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from typing import Any, Awaitable, Callable, Collection, Dict, List, Optional, Set, Tuple

import pytest
from chia_rs import ELIGIBLE_FOR_DEDUP, ELIGIBLE_FOR_FF, G1Element, G2Element
from chia_rs import ELIGIBLE_FOR_DEDUP, ELIGIBLE_FOR_FF, AugSchemeMPL, G2Element
from chiabip158 import PyBIP158

from chia._tests.util.misc import invariant_check_mempool
Expand Down Expand Up @@ -374,10 +374,12 @@ def test_compute_assert_height(conds: SpendBundleConditions, expected: TimelockC
assert compute_assert_height(coin_records, conds) == expected


def spend_bundle_from_conditions(conditions: List[List[Any]], coin: Coin = TEST_COIN) -> SpendBundle:
def spend_bundle_from_conditions(
conditions: List[List[Any]], coin: Coin = TEST_COIN, aggsig: G2Element = G2Element()
) -> SpendBundle:
solution = Program.to(conditions)
coin_spend = make_spend(coin, IDENTITY_PUZZLE, solution)
return SpendBundle([coin_spend], G2Element())
return SpendBundle([coin_spend], aggsig)


async def add_spendbundle(
Expand All @@ -393,8 +395,9 @@ async def generate_and_add_spendbundle(
mempool_manager: MempoolManager,
conditions: List[List[Any]],
coin: Coin = TEST_COIN,
aggsig: G2Element = G2Element(),
) -> Tuple[SpendBundle, bytes32, Tuple[Optional[uint64], MempoolInclusionStatus, Optional[Err]]]:
sb = spend_bundle_from_conditions(conditions, coin)
sb = spend_bundle_from_conditions(conditions, coin, aggsig)
sb_name = sb.name()
result = await add_spendbundle(mempool_manager, sb, sb_name)
return (sb, sb_name, result)
Expand Down Expand Up @@ -567,11 +570,14 @@ async def test_same_sb_twice_with_eligible_coin() -> None:
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 2],
]
sb1 = spend_bundle_from_conditions(sb1_conditions)
sk = AugSchemeMPL.key_gen(b"5" * 32)
g1 = sk.get_g1()
sig = AugSchemeMPL.sign(sk, IDENTITY_PUZZLE_HASH, g1)
sb2_conditions = [
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 3],
[ConditionOpcode.AGG_SIG_UNSAFE, G1Element(), IDENTITY_PUZZLE_HASH],
[ConditionOpcode.AGG_SIG_UNSAFE, g1, IDENTITY_PUZZLE_HASH],
]
sb2 = spend_bundle_from_conditions(sb2_conditions, TEST_COIN2)
sb2 = spend_bundle_from_conditions(sb2_conditions, TEST_COIN2, sig)
sb = SpendBundle.aggregate([sb1, sb2])
sb_name = sb.name()
result = await add_spendbundle(mempool_manager, sb, sb_name)
Expand All @@ -591,13 +597,16 @@ async def test_sb_twice_with_eligible_coin_and_different_spends_order() -> None:
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 2],
]
sb1 = spend_bundle_from_conditions(sb1_conditions)
sb2_conditions = [
sk = AugSchemeMPL.key_gen(b"6" * 32)
g1 = sk.get_g1()
sig = AugSchemeMPL.sign(sk, IDENTITY_PUZZLE_HASH, g1)
sb2_conditions: List[List[Any]] = [
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 3],
[ConditionOpcode.AGG_SIG_UNSAFE, G1Element(), IDENTITY_PUZZLE_HASH],
[ConditionOpcode.AGG_SIG_UNSAFE, bytes(g1), IDENTITY_PUZZLE_HASH],
]
sb2 = spend_bundle_from_conditions(sb2_conditions, TEST_COIN2)
sb3_conditions = [[ConditionOpcode.AGG_SIG_UNSAFE, G1Element(), IDENTITY_PUZZLE_HASH]]
sb3 = spend_bundle_from_conditions(sb3_conditions, TEST_COIN3)
sb2 = spend_bundle_from_conditions(sb2_conditions, TEST_COIN2, sig)
sb3_conditions = [[ConditionOpcode.AGG_SIG_UNSAFE, bytes(g1), IDENTITY_PUZZLE_HASH]]
sb3 = spend_bundle_from_conditions(sb3_conditions, TEST_COIN3, sig)
sb = SpendBundle.aggregate([sb1, sb2, sb3])
sb_name = sb.name()
reordered_sb = SpendBundle.aggregate([sb3, sb1, sb2])
Expand Down Expand Up @@ -1029,12 +1038,16 @@ async def get_unspent_lineage_info_for_puzzle_hash(_: bytes32) -> Optional[Unspe

async def make_and_send_big_cost_sb(coin: Coin) -> None:
conditions = []
g1 = G1Element()
sk = AugSchemeMPL.key_gen(b"7" * 32)
g1 = sk.get_g1()
sig = AugSchemeMPL.sign(sk, IDENTITY_PUZZLE_HASH, g1)
aggsig = G2Element()
for _ in range(169):
conditions.append([ConditionOpcode.AGG_SIG_UNSAFE, g1, IDENTITY_PUZZLE_HASH])
aggsig += sig
conditions.append([ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, coin.amount - 10_000_000])
# Create a spend bundle with a big enough cost that gets it close to the limit
_, _, res = await generate_and_add_spendbundle(mempool_manager, conditions, coin)
_, _, res = await generate_and_add_spendbundle(mempool_manager, conditions, coin, aggsig)
assert res[1] == MempoolInclusionStatus.SUCCESS

mempool_manager, coins = await setup_mempool_with_coins(
Expand All @@ -1057,12 +1070,18 @@ async def make_and_send_big_cost_sb(coin: Coin) -> None:
# Create 4 extra spend bundles with smaller FPC and smaller costs
extra_sbs = []
extra_additions = []
sk = AugSchemeMPL.key_gen(b"8" * 32)
g1 = sk.get_g1()
sig = AugSchemeMPL.sign(sk, b"foobar", g1)
for i in range(num_skipped_items + 1, num_skipped_items + 5):
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, coins[i].amount - 30_000]]
# Make the first of these without eligible coins
if i == num_skipped_items + 1:
conditions.append([ConditionOpcode.AGG_SIG_UNSAFE, G1Element(), IDENTITY_PUZZLE_HASH])
sb, _, res = await generate_and_add_spendbundle(mempool_manager, conditions, coins[i])
conditions.append([ConditionOpcode.AGG_SIG_UNSAFE, bytes(g1), b"foobar"])
aggsig = sig
else:
aggsig = G2Element()
sb, _, res = await generate_and_add_spendbundle(mempool_manager, conditions, coins[i], aggsig)
extra_sbs.append(sb)
coin = Coin(coins[i].name(), IDENTITY_PUZZLE_HASH, uint64(coins[i].amount - 30_000))
extra_additions.append(coin)
Expand Down Expand Up @@ -1169,9 +1188,13 @@ async def get_coin_records(coin_ids: Collection[bytes32]) -> List[CoinRecord]:

def make_test_spendbundle(coin: Coin, *, fee: int = 0, eligible_spend: bool = False) -> SpendBundle:
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, uint64(coin.amount - fee)]]
sig = G2Element()
if not eligible_spend:
conditions.append([ConditionOpcode.AGG_SIG_UNSAFE, G1Element(), IDENTITY_PUZZLE_HASH])
return spend_bundle_from_conditions(conditions, coin)
sk = AugSchemeMPL.key_gen(b"2" * 32)
g1 = sk.get_g1()
sig = AugSchemeMPL.sign(sk, b"foobar", g1)
conditions.append([ConditionOpcode.AGG_SIG_UNSAFE, g1, b"foobar"])
return spend_bundle_from_conditions(conditions, coin, sig)


async def send_spendbundle(
Expand Down Expand Up @@ -1343,11 +1366,16 @@ def test_run_for_cost_max_cost() -> None:

def test_dedup_info_nothing_to_do() -> None:
# No eligible coins, nothing to deduplicate, item gets considered normally

sk = AugSchemeMPL.key_gen(b"3" * 32)
g1 = sk.get_g1()
sig = AugSchemeMPL.sign(sk, b"foobar", g1)

conditions = [
[ConditionOpcode.AGG_SIG_UNSAFE, G1Element(), IDENTITY_PUZZLE_HASH],
[ConditionOpcode.AGG_SIG_UNSAFE, g1, b"foobar"],
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 1],
]
sb = spend_bundle_from_conditions(conditions, TEST_COIN)
sb = spend_bundle_from_conditions(conditions, TEST_COIN, sig)
mempool_item = mempool_item_from_spendbundle(sb)
assert mempool_item.npc_result.conds is not None
eligible_coin_spends = EligibleCoinSpends()
Expand Down Expand Up @@ -1453,11 +1481,14 @@ def test_dedup_info_eligible_3rd_time_another_2nd_time_and_one_non_eligible() ->
)
sb1 = spend_bundle_from_conditions(initial_conditions, TEST_COIN)
sb2 = spend_bundle_from_conditions(second_conditions, TEST_COIN2)
sk = AugSchemeMPL.key_gen(b"4" * 32)
g1 = sk.get_g1()
sig = AugSchemeMPL.sign(sk, b"foobar", g1)
sb3_conditions = [
[ConditionOpcode.AGG_SIG_UNSAFE, G1Element(), IDENTITY_PUZZLE_HASH],
[ConditionOpcode.AGG_SIG_UNSAFE, g1, b"foobar"],
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 4],
]
sb3 = spend_bundle_from_conditions(sb3_conditions, TEST_COIN3)
sb3 = spend_bundle_from_conditions(sb3_conditions, TEST_COIN3, sig)
sb = SpendBundle.aggregate([sb1, sb2, sb3])
mempool_item = mempool_item_from_spendbundle(sb)
assert mempool_item.npc_result.conds is not None
Expand Down
45 changes: 32 additions & 13 deletions chia/_tests/core/mempool/test_singleton_fast_forward.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,11 @@ async def test_process_fast_forward_spends_nothing_to_do() -> None:
async def get_unspent_lineage_info_for_puzzle_hash(_: bytes32) -> Optional[UnspentLineageInfo]:
assert False # pragma: no cover

conditions = [[ConditionOpcode.AGG_SIG_UNSAFE, G1Element(), IDENTITY_PUZZLE_HASH]]
sb = spend_bundle_from_conditions(conditions, TEST_COIN)
sk = AugSchemeMPL.key_gen(b"b" * 32)
g1 = sk.get_g1()
sig = AugSchemeMPL.sign(sk, b"foobar", g1)
conditions = [[ConditionOpcode.AGG_SIG_UNSAFE, bytes(g1), b"foobar"]]
sb = spend_bundle_from_conditions(conditions, TEST_COIN, sig)
item = mempool_item_from_spendbundle(sb)
# This coin is not eligible for fast forward
assert item.bundle_coin_spends[TEST_COIN_ID].eligible_for_fast_forward is False
Expand Down Expand Up @@ -252,16 +255,19 @@ async def make_and_send_spend_bundle(
sim_client: SimClient,
coin_spends: List[CoinSpend],
is_eligible_for_ff: bool = True,
*,
is_launcher_coin: bool = False,
signing_puzzle: Optional[Program] = None,
signing_coin: Optional[Coin] = None,
aggsig: G2Element = G2Element(),
) -> Tuple[MempoolInclusionStatus, Optional[Err]]:
if is_launcher_coin or not is_eligible_for_ff:
assert signing_puzzle is not None
assert signing_coin is not None
signature = sign_delegated_puz(signing_puzzle, signing_coin)
signature += aggsig
else:
signature = G2Element()
signature = aggsig
spend_bundle = SpendBundle(coin_spends, signature)
status, error = await sim_client.push_tx(spend_bundle)
if error is None:
Expand Down Expand Up @@ -403,8 +409,12 @@ async def test_singleton_fast_forward_different_block(is_eligible_for_ff: bool)
# Let's spend this first version, to create a bigger singleton child
singleton_puzzle_hash = eve_coin_spend.coin.puzzle_hash
inner_puzzle_hash = inner_puzzle.get_tree_hash()
inner_conditions = [
[ConditionOpcode.AGG_SIG_UNSAFE, G1Element(), IDENTITY_PUZZLE_HASH],

sk = AugSchemeMPL.key_gen(b"1" * 32)
g1 = sk.get_g1()
sig = AugSchemeMPL.sign(sk, b"foobar", g1)
inner_conditions: List[List[Any]] = [
[ConditionOpcode.AGG_SIG_UNSAFE, bytes(g1), b"foobar"],
[ConditionOpcode.CREATE_COIN, inner_puzzle_hash, SINGLETON_CHILD_AMOUNT],
]
singleton_coin_spend, singleton_signing_puzzle = make_singleton_coin_spend(
Expand All @@ -423,6 +433,7 @@ async def test_singleton_fast_forward_different_block(is_eligible_for_ff: bool)
is_eligible_for_ff,
signing_puzzle=singleton_signing_puzzle,
signing_coin=singleton,
aggsig=sig,
)
unspent_lineage_info = await sim_client.service.coin_store.get_unspent_lineage_info_for_puzzle_hash(
singleton_puzzle_hash
Expand All @@ -448,6 +459,7 @@ async def test_singleton_fast_forward_different_block(is_eligible_for_ff: bool)
is_eligible_for_ff,
signing_puzzle=singleton_signing_puzzle,
signing_coin=singleton,
aggsig=sig,
)
if is_eligible_for_ff:
# Instead of rejecting this as double spend, we perform a fast forward,
Expand Down Expand Up @@ -492,8 +504,11 @@ async def test_singleton_fast_forward_same_block() -> None:
# Let's spend this first version, to create a bigger singleton child
singleton_puzzle_hash = eve_coin_spend.coin.puzzle_hash
inner_puzzle_hash = inner_puzzle.get_tree_hash()
inner_conditions = [
[ConditionOpcode.AGG_SIG_UNSAFE, G1Element(), IDENTITY_PUZZLE_HASH],
sk = AugSchemeMPL.key_gen(b"9" * 32)
g1 = sk.get_g1()
sig = AugSchemeMPL.sign(sk, b"foobar", g1)
inner_conditions: List[List[Any]] = [
[ConditionOpcode.AGG_SIG_UNSAFE, bytes(g1), b"foobar"],
[ConditionOpcode.CREATE_COIN, inner_puzzle_hash, SINGLETON_CHILD_AMOUNT],
]
singleton_coin_spend, _ = make_singleton_coin_spend(eve_coin_spend, singleton, inner_puzzle, inner_conditions)
Expand All @@ -503,7 +518,7 @@ async def test_singleton_fast_forward_same_block() -> None:
Program.to([[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, remaining_coin.amount - diff_to_balance]])
)
remaining_coin_spend = CoinSpend(remaining_coin, IDENTITY_PUZZLE, remaining_spend_solution)
await make_and_send_spend_bundle(sim, sim_client, [remaining_coin_spend, singleton_coin_spend])
await make_and_send_spend_bundle(sim, sim_client, [remaining_coin_spend, singleton_coin_spend], aggsig=sig)
unspent_lineage_info = await sim_client.service.coin_store.get_unspent_lineage_info_for_puzzle_hash(
singleton_puzzle_hash
)
Expand All @@ -519,19 +534,23 @@ async def test_singleton_fast_forward_same_block() -> None:
# Now let's send 3 arbitrary spends of the already spent singleton in
# one block. They should all properly fast forward
random_amounts = [21, 17, 11]
signature = G2Element()

sk = AugSchemeMPL.key_gen(b"a" * 32)
g1 = sk.get_g1()
sig = AugSchemeMPL.sign(sk, b"foobar", g1)
for i in range(3):
# This cost adjustment allows us to maintain the order of spends due to fee per
# cost and amounts dynamics
cost_factor = (i + 1) * 5
inner_conditions = [
[ConditionOpcode.AGG_SIG_UNSAFE, G1Element(), IDENTITY_PUZZLE_HASH] for _ in range(cost_factor)
]
inner_conditions = [[ConditionOpcode.AGG_SIG_UNSAFE, bytes(g1), b"foobar"] for _ in range(cost_factor)]
aggsig = G2Element()
for _ in range(cost_factor):
aggsig += sig
inner_conditions.append([ConditionOpcode.CREATE_COIN, inner_puzzle_hash, random_amounts[i]])
singleton_coin_spend, _ = make_singleton_coin_spend(
eve_coin_spend, singleton, inner_puzzle, inner_conditions
)
status, error = await sim_client.push_tx(SpendBundle([singleton_coin_spend], signature))
status, error = await sim_client.push_tx(SpendBundle([singleton_coin_spend], aggsig))
assert error is None
assert status == MempoolInclusionStatus.SUCCESS

Expand Down

0 comments on commit bf6aa50

Please sign in to comment.