Skip to content

Commit

Permalink
Fork infrastructure (#15299)
Browse files Browse the repository at this point in the history
* remove softfork-logic for 1.7 softfork (which has already activated)

* add new constants for soft-fork3, hard-fork and the other plot-filter adjustments
  • Loading branch information
arvidn authored May 19, 2023
1 parent c5714b1 commit 621c75e
Show file tree
Hide file tree
Showing 13 changed files with 45 additions and 51 deletions.
4 changes: 1 addition & 3 deletions chia/consensus/block_body_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -480,9 +480,7 @@ async def validate_block_body(
pairs_msgs: List[bytes] = []
if npc_result:
assert npc_result.conds is not None
pairs_pks, pairs_msgs = pkm_pairs(
npc_result.conds, constants.AGG_SIG_ME_ADDITIONAL_DATA, soft_fork=height >= constants.SOFT_FORK_HEIGHT
)
pairs_pks, pairs_msgs = pkm_pairs(npc_result.conds, constants.AGG_SIG_ME_ADDITIONAL_DATA)

# 22. Verify aggregated signature
# TODO: move this to pre_validate_blocks_multiprocessing so we can sync faster
Expand Down
14 changes: 12 additions & 2 deletions chia/consensus/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,22 @@ class ConsensusConstants:
MAX_GENERATOR_SIZE: uint32
MAX_GENERATOR_REF_LIST_SIZE: uint32
POOL_SUB_SLOT_ITERS: uint64
# soft fork initiated in 1.7.0 release
SOFT_FORK_HEIGHT: uint32

# soft fork initiated in 1.8.0 release
SOFT_FORK2_HEIGHT: uint32

# soft fork initiated in 2.0 release
SOFT_FORK3_HEIGHT: uint32

# the hard fork planned with the 2.0 release
# this is the block with the first plot filter adjustment
HARD_FORK_HEIGHT: uint32

# the plot filter adjustment heights
PLOT_FILTER_128_HEIGHT: uint32
PLOT_FILTER_64_HEIGHT: uint32
PLOT_FILTER_32_HEIGHT: uint32

def replace(self, **changes: object) -> "ConsensusConstants":
return dataclasses.replace(self, **changes)

Expand Down
11 changes: 10 additions & 1 deletion chia/consensus/default_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,17 @@
"MAX_GENERATOR_SIZE": 1000000,
"MAX_GENERATOR_REF_LIST_SIZE": 512, # Number of references allowed in the block generator ref list
"POOL_SUB_SLOT_ITERS": 37600000000, # iters limit * NUM_SPS
"SOFT_FORK_HEIGHT": 3630000,
"SOFT_FORK2_HEIGHT": 3886635,
# Spetember 2023
"SOFT_FORK3_HEIGHT": 4200000,
# June 2024
"HARD_FORK_HEIGHT": 5496000,
# June 2027
"PLOT_FILTER_128_HEIGHT": 10542000,
# June 2030
"PLOT_FILTER_64_HEIGHT": 15592000,
# June 2033
"PLOT_FILTER_32_HEIGHT": 20643000,
}


Expand Down
6 changes: 1 addition & 5 deletions chia/consensus/multiprocess_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,7 @@ def batch_pre_validate_blocks(
if validate_signatures:
if npc_result is not None and block.transactions_info is not None:
assert npc_result.conds
pairs_pks, pairs_msgs = pkm_pairs(
npc_result.conds,
constants.AGG_SIG_ME_ADDITIONAL_DATA,
soft_fork=block.height >= constants.SOFT_FORK_HEIGHT,
)
pairs_pks, pairs_msgs = pkm_pairs(npc_result.conds, constants.AGG_SIG_ME_ADDITIONAL_DATA)
# Using AugSchemeMPL.aggregate_verify, so it's safe to use from_bytes_unchecked
pks_objects: List[G1Element] = [G1Element.from_bytes_unchecked(pk) for pk in pairs_pks]
if not AugSchemeMPL.aggregate_verify(
Expand Down
6 changes: 1 addition & 5 deletions chia/full_node/full_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -1879,11 +1879,7 @@ async def add_unfinished_block(
# blockchain.run_generator throws on errors, so npc_result is
# guaranteed to represent a successful run
assert npc_result.conds is not None
pairs_pks, pairs_msgs = pkm_pairs(
npc_result.conds,
self.constants.AGG_SIG_ME_ADDITIONAL_DATA,
soft_fork=height >= self.constants.SOFT_FORK_HEIGHT,
)
pairs_pks, pairs_msgs = pkm_pairs(npc_result.conds, self.constants.AGG_SIG_ME_ADDITIONAL_DATA)
if not cached_bls.aggregate_verify(
pairs_pks, pairs_msgs, block.transactions_info.aggregated_signature, True
):
Expand Down
4 changes: 1 addition & 3 deletions chia/full_node/mempool_check_conditions.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,8 @@ def get_name_puzzle_conditions(
) -> NPCResult:
if mempool_mode:
flags = MEMPOOL_MODE
elif height >= constants.SOFT_FORK_HEIGHT:
flags = LIMIT_STACK
else:
flags = 0
flags = LIMIT_STACK

if height >= constants.SOFT_FORK2_HEIGHT:
flags = flags | ENABLE_ASSERT_BEFORE | NO_RELATIVE_CONDITIONS_ON_EPHEMERAL
Expand Down
2 changes: 1 addition & 1 deletion chia/full_node/mempool_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def validate_clvm_and_signature(
pks: List[bytes48] = []
msgs: List[bytes] = []
assert result.conds is not None
pks, msgs = pkm_pairs(result.conds, additional_data, soft_fork=True)
pks, msgs = pkm_pairs(result.conds, additional_data)

# Verify aggregated signature
cache: LRUCache[bytes32, GTElement] = LRUCache(10000)
Expand Down
2 changes: 0 additions & 2 deletions chia/server/start_full_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,6 @@ async def async_main(service_config: Dict[str, Any]) -> int:
# activate softforks immediately on testnet
if "SOFT_FORK2_HEIGHT" not in overrides:
overrides["SOFT_FORK2_HEIGHT"] = 0
if "SOFT_FORK_HEIGHT" not in overrides:
overrides["SOFT_FORK_HEIGHT"] = 0
updated_constants = DEFAULT_CONSTANTS.replace_str_to_bytes(**overrides)
initialize_service_logging(service_name=SERVICE_NAME, config=config)
service = create_full_node_service(DEFAULT_ROOT_PATH, config, updated_constants)
Expand Down
6 changes: 2 additions & 4 deletions chia/util/condition_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,13 @@ def parse_sexp_to_conditions(sexp: Program) -> List[ConditionWithArgs]:
return [parse_sexp_to_condition(s) for s in sexp.as_iter()]


def pkm_pairs(
conditions: SpendBundleConditions, additional_data: bytes, *, soft_fork: bool
) -> Tuple[List[bytes48], List[bytes]]:
def pkm_pairs(conditions: SpendBundleConditions, additional_data: bytes) -> Tuple[List[bytes48], List[bytes]]:
ret: Tuple[List[bytes48], List[bytes]] = ([], [])

for pk, msg in conditions.agg_sig_unsafe:
ret[0].append(bytes48(pk))
ret[1].append(msg)
if soft_fork and msg.endswith(additional_data):
if msg.endswith(additional_data):
raise ConsensusError(Err.INVALID_CONDITION)

for spend in conditions.spends:
Expand Down
1 change: 0 additions & 1 deletion chia/util/initial-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ network_overrides: &network_overrides
GENESIS_PRE_FARM_POOL_PUZZLE_HASH: d23da14695a188ae5708dd152263c4db883eb27edeb936178d4d988b8f3ce5fc
MEMPOOL_BLOCK_BUFFER: 10
MIN_PLOT_SIZE: 18
SOFT_FORK_HEIGHT: 0
SOFT_FORK2_HEIGHT: 0
config:
mainnet:
Expand Down
2 changes: 1 addition & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def db_version(request) -> int:
return request.param


@pytest.fixture(scope="function", params=[1000000, 3630000, 3886635])
@pytest.fixture(scope="function", params=[1000000, 3886635, 4200000, 5496000])
def softfork_height(request) -> int:
return request.param

Expand Down
36 changes: 14 additions & 22 deletions tests/core/mempool/test_mempool.py
Original file line number Diff line number Diff line change
Expand Up @@ -2525,21 +2525,21 @@ class TestPkmPairs:
pk1 = G1Element.generator()
pk2 = G1Element.generator()

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

def test_no_agg_sigs(self, softfork):
def test_no_agg_sigs(self):
# one create coin: h1 amount: 1 and not hint
spends = [Spend(self.h3, self.h4, None, None, 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)
pks, msgs = pkm_pairs(conds, b"foobar")
assert pks == []
assert msgs == []

def test_agg_sig_me(self, softfork):
def test_agg_sig_me(self):
spends = [
Spend(
self.h1,
Expand All @@ -2556,48 +2556,40 @@ def test_agg_sig_me(self, softfork):
)
]
conds = SpendBundleConditions(spends, 0, 0, 0, None, None, [], 0, 0, 0)
pks, msgs = pkm_pairs(conds, b"foobar", soft_fork=softfork)
pks, msgs = pkm_pairs(conds, b"foobar")
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):
def test_agg_sig_unsafe(self):
conds = SpendBundleConditions(
[], 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)
pks, msgs = pkm_pairs(conds, b"foobar")
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):
def test_agg_sig_mixed(self):
spends = [Spend(self.h1, self.h2, None, None, 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)
pks, msgs = pkm_pairs(conds, b"foobar")
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
)
pks, msgs = pkm_pairs(conds, b"msg1", soft_fork=False)
assert [bytes(pk) for pk in pks] == [bytes(self.pk1), bytes(self.pk2)]
assert msgs == [b"msg1", b"msg2"]

pks, msgs = pkm_pairs(conds, b"msg2", soft_fork=False)
assert [bytes(pk) for pk in pks] == [bytes(self.pk1), bytes(self.pk2)]
assert msgs == [b"msg1", b"msg2"]

with pytest.raises(ConsensusError, match="INVALID_CONDITION"):
pkm_pairs(conds, b"msg1", soft_fork=True)
pkm_pairs(conds, b"msg1")

with pytest.raises(ConsensusError, match="INVALID_CONDITION"):
pkm_pairs(conds, b"sg1", soft_fork=True)
pkm_pairs(conds, b"sg1")

with pytest.raises(ConsensusError, match="INVALID_CONDITION"):
pkm_pairs(conds, b"msg2", soft_fork=True)
pkm_pairs(conds, b"msg2")

with pytest.raises(ConsensusError, match="INVALID_CONDITION"):
pkm_pairs(conds, b"g2", soft_fork=True)
pkm_pairs(conds, b"g2")


class TestPkmPairsForConditionDict:
Expand Down
2 changes: 1 addition & 1 deletion tools/analyze-chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def default_call(
# create hash_key list for aggsig check
pairs_pks: List[bytes48] = []
pairs_msgs: List[bytes] = []
pairs_pks, pairs_msgs = pkm_pairs(result, DEFAULT_CONSTANTS.AGG_SIG_ME_ADDITIONAL_DATA, soft_fork=False)
pairs_pks, pairs_msgs = pkm_pairs(result, DEFAULT_CONSTANTS.AGG_SIG_ME_ADDITIONAL_DATA)
pairs_g1s = [G1Element.from_bytes(x) for x in pairs_pks]
assert block.transactions_info is not None
assert block.transactions_info.aggregated_signature is not None
Expand Down

0 comments on commit 621c75e

Please sign in to comment.