Fork infrastructure (#15299)

* 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
This commit is contained in:
Arvid Norberg 2023-05-19 03:20:11 +02:00 committed by GitHub
parent c5714b1720
commit 621c75e4ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 46 additions and 52 deletions

View File

@ -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

View File

@ -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)

View File

@ -56,8 +56,17 @@ default_kwargs = {
"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,
}

View File

@ -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(

View File

@ -1879,11 +1879,7 @@ class FullNode:
# 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
):

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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,
@ -2556,22 +2556,22 @@ class TestPkmPairs:
)
]
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"]
@ -2579,25 +2579,17 @@ class TestPkmPairs:
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")
with pytest.raises(ConsensusError, match="INVALID_CONDITION"):
pkm_pairs(conds, b"msg1", soft_fork=True)
pkm_pairs(conds, b"sg1")
with pytest.raises(ConsensusError, match="INVALID_CONDITION"):
pkm_pairs(conds, b"sg1", soft_fork=True)
pkm_pairs(conds, b"msg2")
with pytest.raises(ConsensusError, match="INVALID_CONDITION"):
pkm_pairs(conds, b"msg2", soft_fork=True)
with pytest.raises(ConsensusError, match="INVALID_CONDITION"):
pkm_pairs(conds, b"g2", soft_fork=True)
pkm_pairs(conds, b"g2")
class TestPkmPairsForConditionDict:

View File

@ -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