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

Bump chia_rs to 0.2.3. and ASSERT_MY_BIRTH_* #14720

Merged
merged 4 commits into from
Mar 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
22 changes: 20 additions & 2 deletions benchmarks/mempool.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,16 @@ async def add_spend_bundles(spend_bundles: List[SpendBundle]) -> None:
npc_result = NPCResult(
None,
SpendBundleConditions(
[Spend(coin_id, bytes32(b" " * 32), None, 0, None, None, [], [], 0)], 0, 0, 0, None, None, [], 0
[Spend(coin_id, bytes32(b" " * 32), None, 0, None, None, None, None, [], [], 0)],
0,
0,
0,
None,
None,
[],
0,
0,
0,
),
uint64(1000000000),
)
Expand All @@ -224,7 +233,16 @@ async def add_spend_bundles(spend_bundles: List[SpendBundle]) -> None:
npc_result = NPCResult(
None,
SpendBundleConditions(
[Spend(coin_id, bytes32(b" " * 32), None, 0, None, None, [], [], 0)], 0, 0, 0, None, None, [], 0
[Spend(coin_id, bytes32(b" " * 32), None, 0, None, None, None, None, [], [], 0)],
0,
0,
0,
None,
None,
[],
0,
0,
0,
),
uint64(1000000000),
)
Expand Down
6 changes: 6 additions & 0 deletions chia/full_node/mempool_check_conditions.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ def mempool_check_time_locks(

for spend in bundle_conds.spends:
unspent = removal_coin_records[bytes32(spend.coin_id)]
if spend.birth_height is not None:
if spend.birth_height != unspent.confirmed_block_index:
return Err.ASSERT_MY_BIRTH_HEIGHT_FAILED
if spend.birth_seconds is not None:
if spend.birth_seconds != unspent.timestamp:
return Err.ASSERT_MY_BIRTH_SECONDS_FAILED
aqk marked this conversation as resolved.
Show resolved Hide resolved
if spend.height_relative is not None:
if prev_transaction_block_height < unspent.confirmed_block_index + spend.height_relative:
return Err.ASSERT_HEIGHT_RELATIVE_FAILED
Expand Down
2 changes: 2 additions & 0 deletions chia/types/condition_opcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ class ConditionOpcode(bytes, enum.Enum):
ASSERT_MY_PARENT_ID = bytes([71])
ASSERT_MY_PUZZLEHASH = bytes([72])
ASSERT_MY_AMOUNT = bytes([73])
ASSERT_MY_BIRTH_SECONDS = bytes([74])
ASSERT_MY_BIRTH_HEIGHT = bytes([75])
arvidn marked this conversation as resolved.
Show resolved Hide resolved

# the conditions below ensure that we're "far enough" in the future

Expand Down
3 changes: 3 additions & 0 deletions chia/util/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ class Err(Enum):
IMPOSSIBLE_HEIGHT_RELATIVE_CONSTRAINTS = 136
IMPOSSIBLE_HEIGHT_ABSOLUTE_CONSTRAINTS = 137

ASSERT_MY_BIRTH_SECONDS_FAILED = 138
ASSERT_MY_BIRTH_HEIGHT_FAILED = 139
arvidn marked this conversation as resolved.
Show resolved Hide resolved


class ValidationError(Exception):
def __init__(self, code: Err, error_msg: str = ""):
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"chiapos==1.0.11", # proof of space
"clvm==0.9.7",
"clvm_tools==0.4.6", # Currying, Program.to, other conveniences
"chia_rs==0.2.2",
"chia_rs==0.2.3",
"clvm-tools-rs==0.1.30", # Rust implementation of clvm_tools' compiler
"aiohttp==3.8.4", # HTTP server for full node rpc
"aiosqlite==0.17.0", # asyncio wrapper for sqlite, to store blocks
Expand Down
17 changes: 17 additions & 0 deletions tests/blockchain/test_blockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -1892,6 +1892,15 @@ async def test_aggsig_garbage(self, empty_blockchain, opcode, with_garbage, expe
@pytest.mark.parametrize(
"opcode,lock_value,expected,with_garbage",
[
(co.ASSERT_MY_BIRTH_HEIGHT, -1, rbr.INVALID_BLOCK, False),
(co.ASSERT_MY_BIRTH_HEIGHT, 0x100000000, rbr.INVALID_BLOCK, False),
(co.ASSERT_MY_BIRTH_HEIGHT, 2, rbr.INVALID_BLOCK, False),
(co.ASSERT_MY_BIRTH_HEIGHT, 3, rbr.NEW_PEAK, False),
(co.ASSERT_MY_BIRTH_SECONDS, -1, rbr.INVALID_BLOCK, False),
(co.ASSERT_MY_BIRTH_SECONDS, 0x10000000000000000, rbr.INVALID_BLOCK, False),
(co.ASSERT_MY_BIRTH_SECONDS, 10029, rbr.INVALID_BLOCK, False),
(co.ASSERT_MY_BIRTH_SECONDS, 10030, rbr.NEW_PEAK, False),
aqk marked this conversation as resolved.
Show resolved Hide resolved
(co.ASSERT_MY_BIRTH_SECONDS, 10031, rbr.INVALID_BLOCK, False),
(co.ASSERT_SECONDS_RELATIVE, -2, rbr.NEW_PEAK, False),
(co.ASSERT_SECONDS_RELATIVE, -1, rbr.NEW_PEAK, False),
(co.ASSERT_SECONDS_RELATIVE, 0, rbr.NEW_PEAK, False),
Expand Down Expand Up @@ -1922,6 +1931,14 @@ async def test_ephemeral_timelock(self, opcode, lock_value, expected, with_garba
else:
constants = test_constants

# if the softfork is not active in this test, fixup all the
# tests to instead expect NEW_PEAK unconditionally
if opcode in [
ConditionOpcode.ASSERT_MY_BIRTH_HEIGHT,
ConditionOpcode.ASSERT_MY_BIRTH_SECONDS,
]:
expected = ReceiveBlockResult.NEW_PEAK

async with make_empty_blockchain(constants) as b:

blocks = bt.get_consecutive_blocks(
Expand Down
21 changes: 20 additions & 1 deletion tests/core/full_node/test_conditions.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,19 @@ class TestConditions:
"opcode,value,expected",
[
# the chain has 4 blocks, the spend is happening in the 5th block
# the coin being spent was created in the 3rd block
# the coin being spent was created in the 3rd block (i.e. block 2)
# ensure invalid heights fail and pass correctly, depending on
# which end of the range they exceed
(co.ASSERT_MY_BIRTH_HEIGHT, -1, Err.ASSERT_MY_BIRTH_HEIGHT_FAILED),
(co.ASSERT_MY_BIRTH_HEIGHT, 0x100000000, Err.ASSERT_MY_BIRTH_HEIGHT_FAILED),
(co.ASSERT_MY_BIRTH_HEIGHT, 3, Err.ASSERT_MY_BIRTH_HEIGHT_FAILED),
(co.ASSERT_MY_BIRTH_HEIGHT, 2, None),
# genesis timestamp is 10000 and each block is 10 seconds
(co.ASSERT_MY_BIRTH_SECONDS, -1, Err.ASSERT_MY_BIRTH_SECONDS_FAILED),
(co.ASSERT_MY_BIRTH_SECONDS, 0x10000000000000000, Err.ASSERT_MY_BIRTH_SECONDS_FAILED),
(co.ASSERT_MY_BIRTH_SECONDS, 10019, Err.ASSERT_MY_BIRTH_SECONDS_FAILED),
(co.ASSERT_MY_BIRTH_SECONDS, 10020, None),
aqk marked this conversation as resolved.
Show resolved Hide resolved
(co.ASSERT_MY_BIRTH_SECONDS, 10021, Err.ASSERT_MY_BIRTH_SECONDS_FAILED),
(co.ASSERT_HEIGHT_RELATIVE, -1, None),
(co.ASSERT_HEIGHT_RELATIVE, 0, None),
(co.ASSERT_HEIGHT_RELATIVE, 0x100000000, Err.ASSERT_HEIGHT_RELATIVE_FAILED),
Expand All @@ -160,6 +170,15 @@ class TestConditions:
)
async def test_condition(self, opcode, value, expected, bt, softfork2):
conditions = Program.to(assemble(f"(({opcode[0]} {value}))"))

# when soft fork 2 is not active, these conditions are also not active,
# and never constrain the block
if not softfork2 and opcode in [
co.ASSERT_MY_BIRTH_HEIGHT,
co.ASSERT_MY_BIRTH_SECONDS,
]:
expected = None

await check_conditions(bt, conditions, expected_err=expected, softfork2=softfork2)

@pytest.mark.asyncio
Expand Down
6 changes: 5 additions & 1 deletion tests/core/full_node/test_generator_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
uint64(5),
None,
None,
None,
None,
[
(phs[2], uint64(123), b""),
(phs[3], uint64(0), b"1" * 300),
Expand All @@ -34,6 +36,8 @@
uint64(2),
None,
None,
None,
None,
[
(phs[5], uint64(123), b""),
(phs[6], uint64(0), b"1" * 300),
Expand All @@ -46,7 +50,7 @@


def test_tx_removals_and_additions() -> None:
conditions = SpendBundleConditions(spends, uint64(0), uint32(0), uint64(0), None, None, [], uint64(0))
conditions = SpendBundleConditions(spends, uint64(0), uint32(0), uint64(0), None, None, [], uint64(0), 0, 0)
expected_rems = [coin_ids[0], coin_ids[1]]
expected_additions = []
for spend in spends:
Expand Down
10 changes: 8 additions & 2 deletions tests/core/full_node/test_hint_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
uint64(5),
None,
None,
None,
None,
[
(phs[2], uint64(123), b""),
(phs[4], uint64(3), b"1" * 32),
Expand All @@ -40,6 +42,8 @@
uint64(6),
None,
None,
None,
None,
[
(phs[7], uint64(123), b""),
(phs[4], uint64(6), b""),
Expand All @@ -55,6 +59,8 @@
uint64(2),
None,
None,
None,
None,
[
(phs[5], uint64(123), b""),
(phs[6], uint64(5), b"1" * 3),
Expand All @@ -77,7 +83,7 @@ async def test_hints_to_add(bt: BlockTools, empty_blockchain: Blockchain) -> Non
br: Optional[BlockRecord] = empty_blockchain.get_peak()
assert br is not None
sbc: SpendBundleConditions = SpendBundleConditions(
spends, uint64(0), uint32(0), uint64(0), None, None, [], uint64(0)
spends, uint64(0), uint32(0), uint64(0), None, None, [], uint64(0), 0, 0
)
npc_res = [NPCResult(None, None, uint64(0)), NPCResult(None, sbc, uint64(0))]

Expand All @@ -99,7 +105,7 @@ async def test_lookup_coin_ids(bt: BlockTools, empty_blockchain: Blockchain) ->
br: Optional[BlockRecord] = empty_blockchain.get_peak()
assert br is not None
sbc: SpendBundleConditions = SpendBundleConditions(
spends, uint64(0), uint32(0), uint64(0), None, None, [], uint64(0)
spends, uint64(0), uint32(0), uint64(0), None, None, [], uint64(0), 0, 0
)
npc_res = [NPCResult(None, None, uint64(0)), NPCResult(None, sbc, uint64(0))]

Expand Down
29 changes: 20 additions & 9 deletions tests/core/mempool/test_mempool.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def make_item(idx: int, cost: uint64 = uint64(80), assert_height=100) -> Mempool
return MempoolItem(
SpendBundle([], G2Element()),
uint64(0),
NPCResult(None, SpendBundleConditions([], 0, 0, 0, None, None, [], cost), cost),
NPCResult(None, SpendBundleConditions([], 0, 0, 0, None, None, [], cost, 0, 0), cost),
spend_bundle_name,
uint32(0),
assert_height,
Expand Down Expand Up @@ -371,6 +371,15 @@ async def test_basic_mempool_manager(self, two_nodes_one_block, wallet_a, self_h
@pytest.mark.parametrize(
"opcode,lock_value,expected",
[
(co.ASSERT_MY_BIRTH_HEIGHT, -1, mis.FAILED),
(co.ASSERT_MY_BIRTH_HEIGHT, 0x100000000, mis.FAILED),
(co.ASSERT_MY_BIRTH_HEIGHT, 5, mis.FAILED),
(co.ASSERT_MY_BIRTH_HEIGHT, 6, mis.SUCCESS),
(co.ASSERT_MY_BIRTH_SECONDS, -1, mis.FAILED),
(co.ASSERT_MY_BIRTH_SECONDS, 0x10000000000000000, mis.FAILED),
(co.ASSERT_MY_BIRTH_SECONDS, 10049, mis.FAILED),
(co.ASSERT_MY_BIRTH_SECONDS, 10050, mis.SUCCESS),
(co.ASSERT_MY_BIRTH_SECONDS, 10051, mis.FAILED),
(co.ASSERT_SECONDS_RELATIVE, -2, mis.SUCCESS),
(co.ASSERT_SECONDS_RELATIVE, -1, mis.SUCCESS),
(co.ASSERT_SECONDS_RELATIVE, 0, mis.SUCCESS),
Expand Down Expand Up @@ -2516,15 +2525,15 @@ class TestPkmPairs:
pk2 = G1Element.generator()

def test_empty_list(self, softfork):
conds = SpendBundleConditions([], 0, 0, 0, None, None, [], 0)
conds = SpendBundleConditions([], 0, 0, 0, None, None, [], 0, 0, 0)
pks, msgs = pkm_pairs(conds, b"foobar", soft_fork=softfork)
assert pks == []
assert msgs == []

def test_no_agg_sigs(self, softfork):
# one create coin: h1 amount: 1 and not hint
spends = [Spend(self.h3, self.h4, None, 0, None, None, [(self.h1, 1, b"")], [], 0)]
conds = SpendBundleConditions(spends, 0, 0, 0, None, None, [], 0)
spends = [Spend(self.h3, self.h4, None, 0, None, None, None, None, [(self.h1, 1, b"")], [], 0)]
conds = SpendBundleConditions(spends, 0, 0, 0, None, None, [], 0, 0, 0)
pks, msgs = pkm_pairs(conds, b"foobar", soft_fork=softfork)
assert pks == []
assert msgs == []
Expand All @@ -2538,34 +2547,36 @@ def test_agg_sig_me(self, softfork):
0,
None,
None,
None,
None,
[],
[(bytes48(self.pk1), b"msg1"), (bytes48(self.pk2), b"msg2")],
0,
)
]
conds = SpendBundleConditions(spends, 0, 0, 0, None, None, [], 0)
conds = SpendBundleConditions(spends, 0, 0, 0, None, None, [], 0, 0, 0)
pks, msgs = pkm_pairs(conds, b"foobar", soft_fork=softfork)
assert [bytes(pk) for pk in pks] == [bytes(self.pk1), bytes(self.pk2)]
assert msgs == [b"msg1" + self.h1 + b"foobar", b"msg2" + self.h1 + b"foobar"]

def test_agg_sig_unsafe(self, softfork):
conds = SpendBundleConditions(
[], 0, 0, 0, None, None, [(bytes48(self.pk1), b"msg1"), (bytes48(self.pk2), b"msg2")], 0
[], 0, 0, 0, None, None, [(bytes48(self.pk1), b"msg1"), (bytes48(self.pk2), b"msg2")], 0, 0, 0
)
pks, msgs = pkm_pairs(conds, b"foobar", soft_fork=softfork)
assert [bytes(pk) for pk in pks] == [bytes(self.pk1), bytes(self.pk2)]
assert msgs == [b"msg1", b"msg2"]

def test_agg_sig_mixed(self, softfork):
spends = [Spend(self.h1, self.h2, None, 0, None, None, [], [(bytes48(self.pk1), b"msg1")], 0)]
conds = SpendBundleConditions(spends, 0, 0, 0, None, None, [(bytes48(self.pk2), b"msg2")], 0)
spends = [Spend(self.h1, self.h2, None, 0, None, None, None, None, [], [(bytes48(self.pk1), b"msg1")], 0)]
conds = SpendBundleConditions(spends, 0, 0, 0, None, None, [(bytes48(self.pk2), b"msg2")], 0, 0, 0)
pks, msgs = pkm_pairs(conds, b"foobar", soft_fork=softfork)
assert [bytes(pk) for pk in pks] == [bytes(self.pk2), bytes(self.pk1)]
assert msgs == [b"msg2", b"msg1" + self.h1 + b"foobar"]

def test_agg_sig_unsafe_restriction(self) -> None:
conds = SpendBundleConditions(
[], 0, 0, 0, None, None, [(bytes48(self.pk1), b"msg1"), (bytes48(self.pk2), b"msg2")], 0
[], 0, 0, 0, None, None, [(bytes48(self.pk1), b"msg1"), (bytes48(self.pk2), b"msg2")], 0, 0, 0
)
pks, msgs = pkm_pairs(conds, b"msg1", soft_fork=False)
assert [bytes(pk) for pk in pks] == [bytes(self.pk1), bytes(self.pk2)]
Expand Down
Loading