mirror of
https://github.com/status-im/eth2.0-specs.git
synced 2025-02-03 06:13:31 +00:00
Merge pull request #3350 from ethereum/remove-is_execution_enabled
Remove `is_execution_enabled` condition since Capella
This commit is contained in:
commit
d018635c96
@ -64,27 +64,12 @@ parameter to the `PayloadAttributes`.
|
|||||||
|
|
||||||
```python
|
```python
|
||||||
def prepare_execution_payload(state: BeaconState,
|
def prepare_execution_payload(state: BeaconState,
|
||||||
pow_chain: Dict[Hash32, PowBlock],
|
|
||||||
safe_block_hash: Hash32,
|
safe_block_hash: Hash32,
|
||||||
finalized_block_hash: Hash32,
|
finalized_block_hash: Hash32,
|
||||||
suggested_fee_recipient: ExecutionAddress,
|
suggested_fee_recipient: ExecutionAddress,
|
||||||
execution_engine: ExecutionEngine) -> Optional[PayloadId]:
|
execution_engine: ExecutionEngine) -> Optional[PayloadId]:
|
||||||
if not is_merge_transition_complete(state):
|
# Verify consistency of the parent hash with respect to the previous execution payload header
|
||||||
is_terminal_block_hash_set = TERMINAL_BLOCK_HASH != Hash32()
|
parent_hash = state.latest_execution_payload_header.block_hash
|
||||||
is_activation_epoch_reached = get_current_epoch(state) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
|
|
||||||
if is_terminal_block_hash_set and not is_activation_epoch_reached:
|
|
||||||
# Terminal block hash is set but activation epoch is not yet reached, no prepare payload call is needed
|
|
||||||
return None
|
|
||||||
|
|
||||||
terminal_pow_block = get_terminal_pow_block(pow_chain)
|
|
||||||
if terminal_pow_block is None:
|
|
||||||
# Pre-merge, no prepare payload call is needed
|
|
||||||
return None
|
|
||||||
# Signify merge via producing on top of the terminal PoW block
|
|
||||||
parent_hash = terminal_pow_block.block_hash
|
|
||||||
else:
|
|
||||||
# Post-merge, normal payload
|
|
||||||
parent_hash = state.latest_execution_payload_header.block_hash
|
|
||||||
|
|
||||||
# Set the forkchoice head and initiate the payload build process
|
# Set the forkchoice head and initiate the payload build process
|
||||||
payload_attributes = PayloadAttributes(
|
payload_attributes = PayloadAttributes(
|
||||||
|
@ -176,9 +176,8 @@ class BeaconState(Container):
|
|||||||
```python
|
```python
|
||||||
def process_block(state: BeaconState, block: BeaconBlock) -> None:
|
def process_block(state: BeaconState, block: BeaconBlock) -> None:
|
||||||
process_block_header(state, block)
|
process_block_header(state, block)
|
||||||
if is_execution_enabled(state, block.body):
|
process_withdrawals(state, block.body.execution_payload)
|
||||||
process_withdrawals(state, block.body.execution_payload)
|
process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) # [Modified in EIP6110]
|
||||||
process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) # [Modified in EIP6110]
|
|
||||||
process_randao(state, block.body)
|
process_randao(state, block.body)
|
||||||
process_eth1_data(state, block.body)
|
process_eth1_data(state, block.body)
|
||||||
process_operations(state, block.body) # [Modified in EIP6110]
|
process_operations(state, block.body) # [Modified in EIP6110]
|
||||||
@ -212,8 +211,7 @@ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
|
|||||||
for_ops(body.bls_to_execution_changes, process_bls_to_execution_change)
|
for_ops(body.bls_to_execution_changes, process_bls_to_execution_change)
|
||||||
|
|
||||||
# [New in EIP6110]
|
# [New in EIP6110]
|
||||||
if is_execution_enabled(state, body):
|
for_ops(body.execution_payload.deposit_receipts, process_deposit_receipt)
|
||||||
for_ops(body.execution_payload.deposit_receipts, process_deposit_receipt)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### New `process_deposit_receipt`
|
#### New `process_deposit_receipt`
|
||||||
@ -240,8 +238,7 @@ def process_deposit_receipt(state: BeaconState, deposit_receipt: DepositReceipt)
|
|||||||
```python
|
```python
|
||||||
def process_execution_payload(state: BeaconState, payload: ExecutionPayload, execution_engine: ExecutionEngine) -> None:
|
def process_execution_payload(state: BeaconState, payload: ExecutionPayload, execution_engine: ExecutionEngine) -> None:
|
||||||
# Verify consistency of the parent hash with respect to the previous execution payload header
|
# Verify consistency of the parent hash with respect to the previous execution payload header
|
||||||
if is_merge_transition_complete(state):
|
assert payload.parent_hash == state.latest_execution_payload_header.block_hash
|
||||||
assert payload.parent_hash == state.latest_execution_payload_header.block_hash
|
|
||||||
# Verify prev_randao
|
# Verify prev_randao
|
||||||
assert payload.prev_randao == get_randao_mix(state, get_current_epoch(state))
|
assert payload.prev_randao == get_randao_mix(state, get_current_epoch(state))
|
||||||
# Verify timestamp
|
# Verify timestamp
|
||||||
|
@ -236,8 +236,7 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None:
|
|||||||
process_block_header(state, block)
|
process_block_header(state, block)
|
||||||
verify_builder_block_bid(state, block)
|
verify_builder_block_bid(state, block)
|
||||||
process_sharded_data(state, block)
|
process_sharded_data(state, block)
|
||||||
if is_execution_enabled(state, block.body):
|
process_execution_payload(state, block, EXECUTION_ENGINE)
|
||||||
process_execution_payload(state, block, EXECUTION_ENGINE)
|
|
||||||
|
|
||||||
if not is_builder_block_slot(block.slot):
|
if not is_builder_block_slot(block.slot):
|
||||||
process_randao(state, block.body)
|
process_randao(state, block.body)
|
||||||
@ -371,8 +370,7 @@ def process_execution_payload(state: BeaconState, block: BeaconBlock, execution_
|
|||||||
payload = block.body.payload_data.value.execution_payload
|
payload = block.body.payload_data.value.execution_payload
|
||||||
|
|
||||||
# Verify consistency of the parent hash with respect to the previous execution payload header
|
# Verify consistency of the parent hash with respect to the previous execution payload header
|
||||||
if is_merge_transition_complete(state):
|
assert payload.parent_hash == state.latest_execution_payload_header.block_hash
|
||||||
assert payload.parent_hash == state.latest_execution_payload_header.block_hash
|
|
||||||
# Verify random
|
# Verify random
|
||||||
assert payload.random == get_randao_mix(state, get_current_epoch(state))
|
assert payload.random == get_randao_mix(state, get_current_epoch(state))
|
||||||
# Verify timestamp
|
# Verify timestamp
|
||||||
|
@ -127,12 +127,13 @@ To obtain an execution payload, a block proposer building a block on top of a `s
|
|||||||
|
|
||||||
```python
|
```python
|
||||||
def prepare_execution_payload(state: BeaconState,
|
def prepare_execution_payload(state: BeaconState,
|
||||||
pow_chain: Dict[Hash32, PowBlock],
|
|
||||||
safe_block_hash: Hash32,
|
safe_block_hash: Hash32,
|
||||||
finalized_block_hash: Hash32,
|
finalized_block_hash: Hash32,
|
||||||
suggested_fee_recipient: ExecutionAddress,
|
suggested_fee_recipient: ExecutionAddress,
|
||||||
execution_engine: ExecutionEngine) -> Optional[PayloadId]:
|
execution_engine: ExecutionEngine,
|
||||||
|
pow_chain: Optional[Dict[Hash32, PowBlock]]=None) -> Optional[PayloadId]:
|
||||||
if not is_merge_transition_complete(state):
|
if not is_merge_transition_complete(state):
|
||||||
|
assert pow_chain is not None
|
||||||
is_terminal_block_hash_set = TERMINAL_BLOCK_HASH != Hash32()
|
is_terminal_block_hash_set = TERMINAL_BLOCK_HASH != Hash32()
|
||||||
is_activation_epoch_reached = get_current_epoch(state) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
|
is_activation_epoch_reached = get_current_epoch(state) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
|
||||||
if is_terminal_block_hash_set and not is_activation_epoch_reached:
|
if is_terminal_block_hash_set and not is_activation_epoch_reached:
|
||||||
|
@ -331,9 +331,9 @@ def process_historical_summaries_update(state: BeaconState) -> None:
|
|||||||
```python
|
```python
|
||||||
def process_block(state: BeaconState, block: BeaconBlock) -> None:
|
def process_block(state: BeaconState, block: BeaconBlock) -> None:
|
||||||
process_block_header(state, block)
|
process_block_header(state, block)
|
||||||
if is_execution_enabled(state, block.body):
|
# [Modified in Capella] Removed `is_execution_enabled` check in Capella
|
||||||
process_withdrawals(state, block.body.execution_payload) # [New in Capella]
|
process_withdrawals(state, block.body.execution_payload) # [New in Capella]
|
||||||
process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) # [Modified in Capella]
|
process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) # [Modified in Capella]
|
||||||
process_randao(state, block.body)
|
process_randao(state, block.body)
|
||||||
process_eth1_data(state, block.body)
|
process_eth1_data(state, block.body)
|
||||||
process_operations(state, block.body) # [Modified in Capella]
|
process_operations(state, block.body) # [Modified in Capella]
|
||||||
@ -408,9 +408,9 @@ def process_withdrawals(state: BeaconState, payload: ExecutionPayload) -> None:
|
|||||||
|
|
||||||
```python
|
```python
|
||||||
def process_execution_payload(state: BeaconState, payload: ExecutionPayload, execution_engine: ExecutionEngine) -> None:
|
def process_execution_payload(state: BeaconState, payload: ExecutionPayload, execution_engine: ExecutionEngine) -> None:
|
||||||
|
# [Modified in Capella] Removed `is_merge_transition_complete` check in Capella
|
||||||
# Verify consistency of the parent hash with respect to the previous execution payload header
|
# Verify consistency of the parent hash with respect to the previous execution payload header
|
||||||
if is_merge_transition_complete(state):
|
assert payload.parent_hash == state.latest_execution_payload_header.block_hash
|
||||||
assert payload.parent_hash == state.latest_execution_payload_header.block_hash
|
|
||||||
# Verify prev_randao
|
# Verify prev_randao
|
||||||
assert payload.prev_randao == get_randao_mix(state, get_current_epoch(state))
|
assert payload.prev_randao == get_randao_mix(state, get_current_epoch(state))
|
||||||
# Verify timestamp
|
# Verify timestamp
|
||||||
|
@ -79,27 +79,12 @@ That is, `state` is the `previous_state` processed through any empty slots up to
|
|||||||
|
|
||||||
```python
|
```python
|
||||||
def prepare_execution_payload(state: BeaconState,
|
def prepare_execution_payload(state: BeaconState,
|
||||||
pow_chain: Dict[Hash32, PowBlock],
|
|
||||||
safe_block_hash: Hash32,
|
safe_block_hash: Hash32,
|
||||||
finalized_block_hash: Hash32,
|
finalized_block_hash: Hash32,
|
||||||
suggested_fee_recipient: ExecutionAddress,
|
suggested_fee_recipient: ExecutionAddress,
|
||||||
execution_engine: ExecutionEngine) -> Optional[PayloadId]:
|
execution_engine: ExecutionEngine) -> Optional[PayloadId]:
|
||||||
if not is_merge_transition_complete(state):
|
# [Modified in Capella] Removed `is_merge_transition_complete` check in Capella
|
||||||
is_terminal_block_hash_set = TERMINAL_BLOCK_HASH != Hash32()
|
parent_hash = state.latest_execution_payload_header.block_hash
|
||||||
is_activation_epoch_reached = get_current_epoch(state) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
|
|
||||||
if is_terminal_block_hash_set and not is_activation_epoch_reached:
|
|
||||||
# Terminal block hash is set but activation epoch is not yet reached, no prepare payload call is needed
|
|
||||||
return None
|
|
||||||
|
|
||||||
terminal_pow_block = get_terminal_pow_block(pow_chain)
|
|
||||||
if terminal_pow_block is None:
|
|
||||||
# Pre-merge, no prepare payload call is needed
|
|
||||||
return None
|
|
||||||
# Signify merge via producing on top of the terminal PoW block
|
|
||||||
parent_hash = terminal_pow_block.block_hash
|
|
||||||
else:
|
|
||||||
# Post-merge, normal payload
|
|
||||||
parent_hash = state.latest_execution_payload_header.block_hash
|
|
||||||
|
|
||||||
# Set the forkchoice head and initiate the payload build process
|
# Set the forkchoice head and initiate the payload build process
|
||||||
payload_attributes = PayloadAttributes(
|
payload_attributes = PayloadAttributes(
|
||||||
|
@ -200,9 +200,8 @@ def verify_kzg_commitments_against_transactions(transactions: Sequence[Transacti
|
|||||||
```python
|
```python
|
||||||
def process_block(state: BeaconState, block: BeaconBlock) -> None:
|
def process_block(state: BeaconState, block: BeaconBlock) -> None:
|
||||||
process_block_header(state, block)
|
process_block_header(state, block)
|
||||||
if is_execution_enabled(state, block.body):
|
process_withdrawals(state, block.body.execution_payload)
|
||||||
process_withdrawals(state, block.body.execution_payload)
|
process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) # [Modified in Deneb]
|
||||||
process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) # [Modified in Deneb]
|
|
||||||
process_randao(state, block.body)
|
process_randao(state, block.body)
|
||||||
process_eth1_data(state, block.body)
|
process_eth1_data(state, block.body)
|
||||||
process_operations(state, block.body)
|
process_operations(state, block.body)
|
||||||
@ -217,8 +216,7 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None:
|
|||||||
```python
|
```python
|
||||||
def process_execution_payload(state: BeaconState, payload: ExecutionPayload, execution_engine: ExecutionEngine) -> None:
|
def process_execution_payload(state: BeaconState, payload: ExecutionPayload, execution_engine: ExecutionEngine) -> None:
|
||||||
# Verify consistency of the parent hash with respect to the previous execution payload header
|
# Verify consistency of the parent hash with respect to the previous execution payload header
|
||||||
if is_merge_transition_complete(state):
|
assert payload.parent_hash == state.latest_execution_payload_header.block_hash
|
||||||
assert payload.parent_hash == state.latest_execution_payload_header.block_hash
|
|
||||||
# Verify prev_randao
|
# Verify prev_randao
|
||||||
assert payload.prev_randao == get_randao_mix(state, get_current_epoch(state))
|
assert payload.prev_randao == get_randao_mix(state, get_current_epoch(state))
|
||||||
# Verify timestamp
|
# Verify timestamp
|
||||||
|
@ -8,7 +8,13 @@ from eth2spec.test.helpers.execution_payload import (
|
|||||||
build_state_with_incomplete_transition,
|
build_state_with_incomplete_transition,
|
||||||
build_state_with_complete_transition,
|
build_state_with_complete_transition,
|
||||||
)
|
)
|
||||||
from eth2spec.test.context import spec_state_test, expect_assertion_error, with_bellatrix_and_later
|
from eth2spec.test.context import (
|
||||||
|
BELLATRIX,
|
||||||
|
expect_assertion_error,
|
||||||
|
spec_state_test,
|
||||||
|
with_bellatrix_and_later,
|
||||||
|
with_phases,
|
||||||
|
)
|
||||||
from eth2spec.test.helpers.state import next_slot
|
from eth2spec.test.helpers.state import next_slot
|
||||||
|
|
||||||
|
|
||||||
@ -117,7 +123,7 @@ def test_invalid_bad_execution_regular_payload(spec, state):
|
|||||||
yield from run_bad_execution_test(spec, state)
|
yield from run_bad_execution_test(spec, state)
|
||||||
|
|
||||||
|
|
||||||
@with_bellatrix_and_later
|
@with_phases([BELLATRIX])
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_bad_parent_hash_first_payload(spec, state):
|
def test_bad_parent_hash_first_payload(spec, state):
|
||||||
state = build_state_with_incomplete_transition(spec, state)
|
state = build_state_with_incomplete_transition(spec, state)
|
||||||
|
@ -10,7 +10,10 @@ from eth2spec.test.helpers.execution_payload import (
|
|||||||
build_randomized_execution_payload
|
build_randomized_execution_payload
|
||||||
)
|
)
|
||||||
from eth2spec.test.context import (
|
from eth2spec.test.context import (
|
||||||
with_bellatrix_and_later, spec_state_test
|
BELLATRIX,
|
||||||
|
with_bellatrix_and_later,
|
||||||
|
with_phases,
|
||||||
|
spec_state_test,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -44,7 +47,7 @@ def test_empty_block_transition_randomized_payload(spec, state):
|
|||||||
yield 'post', state
|
yield 'post', state
|
||||||
|
|
||||||
|
|
||||||
@with_bellatrix_and_later
|
@with_phases([BELLATRIX])
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_is_execution_enabled_false(spec, state):
|
def test_is_execution_enabled_false(spec, state):
|
||||||
# Set `latest_execution_payload_header` to empty
|
# Set `latest_execution_payload_header` to empty
|
||||||
|
@ -4,9 +4,12 @@ from typing import Optional
|
|||||||
from eth2spec.test.helpers.pow_block import (
|
from eth2spec.test.helpers.pow_block import (
|
||||||
prepare_random_pow_chain,
|
prepare_random_pow_chain,
|
||||||
)
|
)
|
||||||
|
from eth2spec.test.helpers.constants import (
|
||||||
|
BELLATRIX,
|
||||||
|
)
|
||||||
from eth2spec.test.context import (
|
from eth2spec.test.context import (
|
||||||
spec_state_test,
|
spec_state_test,
|
||||||
with_bellatrix_and_later,
|
with_phases,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -30,7 +33,7 @@ expected_results = [
|
|||||||
# it would return the first block (IS_HEAD_PARENT_BLOCK).
|
# it would return the first block (IS_HEAD_PARENT_BLOCK).
|
||||||
|
|
||||||
|
|
||||||
@with_bellatrix_and_later
|
@with_phases([BELLATRIX])
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_get_pow_block_at_terminal_total_difficulty(spec, state):
|
def test_get_pow_block_at_terminal_total_difficulty(spec, state):
|
||||||
for result in expected_results:
|
for result in expected_results:
|
||||||
@ -90,7 +93,7 @@ prepare_execution_payload_expected_results = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@with_bellatrix_and_later
|
@with_phases([BELLATRIX])
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_prepare_execution_payload(spec, state):
|
def test_prepare_execution_payload(spec, state):
|
||||||
for result in prepare_execution_payload_expected_results:
|
for result in prepare_execution_payload_expected_results:
|
||||||
@ -157,11 +160,11 @@ def test_prepare_execution_payload(spec, state):
|
|||||||
|
|
||||||
payload_id = spec.prepare_execution_payload(
|
payload_id = spec.prepare_execution_payload(
|
||||||
state=state,
|
state=state,
|
||||||
pow_chain=pow_chain.to_dict(),
|
|
||||||
safe_block_hash=safe_block_hash,
|
safe_block_hash=safe_block_hash,
|
||||||
finalized_block_hash=finalized_block_hash,
|
finalized_block_hash=finalized_block_hash,
|
||||||
suggested_fee_recipient=suggested_fee_recipient,
|
suggested_fee_recipient=suggested_fee_recipient,
|
||||||
execution_engine=TestEngine(),
|
execution_engine=TestEngine(),
|
||||||
|
pow_chain=pow_chain.to_dict(),
|
||||||
)
|
)
|
||||||
assert payload_id == result_payload_id
|
assert payload_id == result_payload_id
|
||||||
|
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
from eth2spec.test.helpers.execution_payload import (
|
||||||
|
build_empty_execution_payload,
|
||||||
|
compute_el_block_hash,
|
||||||
|
build_state_with_incomplete_transition,
|
||||||
|
)
|
||||||
|
from eth2spec.test.context import (
|
||||||
|
spec_state_test,
|
||||||
|
with_capella_and_later,
|
||||||
|
)
|
||||||
|
from eth2spec.test.helpers.state import next_slot
|
||||||
|
from eth2spec.test.bellatrix.block_processing.test_process_execution_payload import run_execution_payload_processing
|
||||||
|
|
||||||
|
|
||||||
|
@with_capella_and_later
|
||||||
|
@spec_state_test
|
||||||
|
def test_invalid_bad_parent_hash_first_payload(spec, state):
|
||||||
|
state = build_state_with_incomplete_transition(spec, state)
|
||||||
|
next_slot(spec, state)
|
||||||
|
|
||||||
|
execution_payload = build_empty_execution_payload(spec, state)
|
||||||
|
execution_payload.parent_hash = b'\x55' * 32
|
||||||
|
execution_payload.block_hash = compute_el_block_hash(spec, execution_payload)
|
||||||
|
|
||||||
|
yield from run_execution_payload_processing(spec, state, execution_payload, valid=False)
|
@ -31,6 +31,29 @@ from eth2spec.test.helpers.deposits import (
|
|||||||
from eth2spec.test.helpers.voluntary_exits import prepare_signed_exits
|
from eth2spec.test.helpers.voluntary_exits import prepare_signed_exits
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# `is_execution_enabled` has been removed from Capella
|
||||||
|
#
|
||||||
|
|
||||||
|
@with_capella_and_later
|
||||||
|
@spec_state_test
|
||||||
|
def test_invalid_is_execution_enabled_false(spec, state):
|
||||||
|
# Set `latest_execution_payload_header` to empty
|
||||||
|
state.latest_execution_payload_header = spec.ExecutionPayloadHeader()
|
||||||
|
yield 'pre', state
|
||||||
|
|
||||||
|
block = build_empty_block_for_next_slot(spec, state)
|
||||||
|
|
||||||
|
# Set `execution_payload` to empty
|
||||||
|
block.body.execution_payload = spec.ExecutionPayload()
|
||||||
|
assert len(block.body.execution_payload.transactions) == 0
|
||||||
|
|
||||||
|
signed_block = state_transition_and_sign_block(spec, state, block, expect_fail=True)
|
||||||
|
|
||||||
|
yield 'blocks', [signed_block]
|
||||||
|
yield 'post', None
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# BLSToExecutionChange
|
# BLSToExecutionChange
|
||||||
#
|
#
|
||||||
|
@ -30,8 +30,9 @@ if __name__ == "__main__":
|
|||||||
bellatrix_mods = combine_mods(_new_bellatrix_mods, altair_mods)
|
bellatrix_mods = combine_mods(_new_bellatrix_mods, altair_mods)
|
||||||
|
|
||||||
_new_capella_mods = {key: 'eth2spec.test.capella.block_processing.test_process_' + key for key in [
|
_new_capella_mods = {key: 'eth2spec.test.capella.block_processing.test_process_' + key for key in [
|
||||||
'deposit',
|
|
||||||
'bls_to_execution_change',
|
'bls_to_execution_change',
|
||||||
|
'deposit',
|
||||||
|
'execution_payload',
|
||||||
'withdrawals',
|
'withdrawals',
|
||||||
]}
|
]}
|
||||||
capella_mods = combine_mods(_new_capella_mods, bellatrix_mods)
|
capella_mods = combine_mods(_new_capella_mods, bellatrix_mods)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user