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

[WIP] epbs (eip-7732) #6443

Draft
wants to merge 47 commits into
base: unstable
Choose a base branch
from
Draft

[WIP] epbs (eip-7732) #6443

wants to merge 47 commits into from

Conversation

Tomi-3-0
Copy link

No description provided.

@Tomi-3-0 Tomi-3-0 changed the title Initial dummy commit epbs (eip-7732) implementation Jul 23, 2024
@Tomi-3-0 Tomi-3-0 changed the title epbs (eip-7732) implementation [WIP] epbs (eip-7732) implementation Jul 27, 2024
@Tomi-3-0 Tomi-3-0 changed the title [WIP] epbs (eip-7732) implementation [WIP] epbs (eip-7732) Jul 27, 2024
Copy link

github-actions bot commented Jul 27, 2024

Unit Test Results

         9 files  ±    0    1 355 suites  +18   38m 20s ⏱️ - 5m 6s
  5 149 tests +  83    4 801 ✔️ +  83  348 💤 ±0  0 ±0 
21 516 runs  +519  21 112 ✔️ +519  404 💤 ±0  0 ±0 

Results for commit da6a476. ± Comparison against base commit f9e44b2.

♻️ This comment has been updated with latest results.

proc is_valid_indexed_payload_attestation(
state: capella.BeaconState, # [TODO] to be replaced with epbs.BeaconState
indexed_payload_attestation: IndexedPayloadAttestation): bool =
# Check if ``indexed_payload_attestation`` is not empty, has sorted and unique indices, and has a valid aggregate signature.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://status-im.github.io/nim-style-guide/formatting.style.html

We strive to follow NEP-1 for style matters - naming, capitalization, 80-character limit etc.

This comment line is quite a bit longer than 80 characters.

This doesn't mean split (break) all the URLs, etc, or other things which for intrinsic reasons just must have longer than 80 character lines, but where it's feasible/practical to wrap at 80, that's the goal.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot to call nimpretty on them. Thank you

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding nimpretty, see https://status-im.github.io/nim-style-guide/formatting.style.html#practical-notes

  • We do not use nimpretty - as of writing (Nim 1.6), it is not stable enough for daily use:

    • Can break working code
    • Naive formatting algorithm

if it works for you, that's great, but it has many flaws, so shouldn't be trusted too much, and shouldn't be used to reformat existing Nimbus code.

@tersec
Copy link
Contributor

tersec commented Aug 6, 2024

Merge branch 'status-im:stable' into epbs

the development branches should generally track unstable, not stable

@Tomi-3-0
Copy link
Author

Tomi-3-0 commented Aug 6, 2024

Merge branch 'status-im:stable' into epbs

the development branches should generally track unstable, not stable

tracks unstable from my end:
...wants to merge 22 commits into status-im:unstable from Tomi-3-0:epbs

indexed_payload_attestation.signature)

# # https://github.com/ethereum/consensus-specs/blob/1508f51b80df5488a515bfedf486f98435200e02/specs/_features/eipxxxx/beacon-chain.md#is_parent_block_full
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the # # https://... intentional?

@tersec
Copy link
Contributor

tersec commented Aug 11, 2024

Are the deletions of NimYAML, gnosis-chain-configs, nim-libbacktrace, nim-libp2p, and sepolia vendored git subrepositories intentional?

2024-08-11T03:19:16,587536883+00:00

@tersec
Copy link
Contributor

tersec commented Sep 9, 2024

Basically I think ef50df0 should be reconsidered

@Tomi-3-0
Copy link
Author

Tomi-3-0 commented Sep 9, 2024

https://github.com/status-im/nimbus-eth2/actions/runs/10752309189/job/29884832856?pr=6443

2024-09-09T16:08:28.1595661Z stack trace: (most recent call last)
2024-09-09T16:08:28.1599116Z /github-runner/workspace/nimbus-eth2/nimbus-eth2/beacon_chain/networking/network_metadata.nim(324, 11) network_metadata
2024-09-09T16:08:28.1602221Z /github-runner/workspace/nimbus-eth2/nimbus-eth2/vendor/nimbus-build-system/vendor/Nim/lib/std/assertions.nim(41, 14) failedAssertImpl
2024-09-09T16:08:28.1605340Z /github-runner/workspace/nimbus-eth2/nimbus-eth2/vendor/nimbus-build-system/vendor/Nim/lib/std/assertions.nim(36, 13) raiseAssert
2024-09-09T16:08:28.1607975Z /github-runner/workspace/nimbus-eth2/nimbus-eth2/vendor/nimbus-build-system/vendor/Nim/lib/system/fatal.nim(53, 5) sysFatal
2024-09-09T16:08:28.1614180Z /github-runner/workspace/nimbus-eth2/nimbus-eth2/vendor/nimbus-build-system/vendor/Nim/lib/system/fatal.nim(53, 5) Error: unhandled exception: /github-runner/workspace/nimbus-eth2/nimbus-eth2/beacon_chain/networking/network_metadata.nim(324, 15) `ConsensusFork.high == ConsensusFork.Electra`  [AssertionDefect]
2024-09-09T16:08:28.2286000Z make: *** [Makefile:447: nimbus_beacon_node] Error 1

can replicate locally by running make nimbus_beacon_node.

General risk with the adding the ConsensusFork: it makes rebasing, etc more difficult. It's a very invasive change and practically, when Nimbus does hardfork updates, I try to separate out sequences of minimal-risk changes, rather than one big feature branch of sorts. This one error is just the beginning -- yes, of course, it's possible to fix, but then there's the next one and the next one and ...

It depends how ePBS should be tested -- my inclination is to probably treat it as a kind of part of the the Electra fork (but declared symbolically, const EbpsFork = ConsensusFork.Electra and systematically using that instead, or similar, to avoid confusion of actually-electra and ePBS), and just figure that this branch can't yet be used properly as part of unstable. Then if/when it's clear which fork it's part of, switch that EpbsFork to the fork in question, after it's already added to ConsensusFork. Combining the two will probably get messy.

We're not going to merge a tentative ConsensusFork anyway so by including that it means it's not going to be merge able anyway.

This makes a lot of sense. Thank you!

{.push raises: [].}

# Minimal preset - epbs
# https://github.com/ethereum/consensus-specs/blob/1508f51b80df5488a515bfedf486f98435200e02/specs/_features/eipxxxx/beacon-chain.md#preset
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

default(ExitQueueInfo) # not used

bsv_use =
when typeof(body).kind >= ConsensusFork.Electra:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This when will always be true. ePBS won't happen before Electra

cfg, state, op, flags, exit_queue_info, cache
)

when typeof(body).kind >= ConsensusFork.Capella:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This when will always be true. ePBS won't happen before Capella


# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.4/specs/_features/eip7732/beacon-chain.md#modified-process_execution_payload
proc process_execution_payload*(
cfg: RuntimeConfig, body: SomeForkyBeaconBlockBody,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can't apply to any random ForkyBlindedBeaconBlockBody, because it has to be a body which applies to an epbs.BeaconState, which means it must be an ePBS block body. No generics necessary/useful here.


var
bsv_use =
when typeof(body).kind >= ConsensusFork.Electra:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This when will always be true. ePBS won't happen before Electra

else:
nil # this is a logic error, effectively assert

when typeof(body).kind >= ConsensusFork.Electra:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This when will always be true. ePBS won't happen before Electra

state, indexed_payload_attestation):
return err("process_payload_attestation: signature verification failed")

var epochParticipation: EpochParticipationFlags
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole section can be more safely phrased as

  let epochParticipation =
    if state.slot mod SLOTS_PER_EPOCH == 0:
      state.previous_epoch_participation
    else:
      state.current_epoch_participation

i.e. a https://nim-lang.org/docs/manual.html#statements-and-expressions-if-expression instead of a https://nim-lang.org/docs/manual.html#statements-and-expressions-if-statement

which works with https://status-im.github.io/nim-style-guide/language.vardecl.html

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think var epochParticipation should still be used since it needs to be passed as a mutable structure, changing just the let to var like so:

    var epochParticipation =
      if state.slot mod SLOTS_PER_EPOCH == 0:
        state.previous_epoch_participation
      else:
        state.current_epoch_participation

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, still an improvement

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One issue though is that if the resulting epochParticipation local variable is modified, the underlying state is not. So it won't accomplish that goal.


for i, index in ptc.pairs:
if payload_attestation.aggregation_bits[i]:
output[pos] = index
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  var
    output: List[ValidatorIndex, Limit PTC_SIZE]

constructs a default 0-item list (it's basically the same thing as a seq[ValidatorIndex] for Nim), so there aren't any existing elements to index into. This line is guaranteed to generate an index out of range defect.

genesisFork: Fork, genesis_validators_root: Eth2Digest,
msg: epbs.SignedExecutionPayloadHeader): Eth2Digest =
# So the epoch doesn't matter when calling get_domain
doAssert genesisFork.previous_version == genesisFork.current_version
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The execution payload headers are not fork-agnostic and this condition won't in general hold. https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.5/specs/_features/eip7732/beacon-chain.md#new-verify_execution_payload_header_signature says:

def verify_execution_payload_header_signature(state: BeaconState, 
                                              signed_header: SignedExecutionPayloadHeader) -> bool:
    # Check the signature
    builder = state.validators[signed_header.message.builder_index]
    signing_root = compute_signing_root(signed_header.message, get_domain(state, DOMAIN_BEACON_BUILDER))
    return bls.Verify(builder.pubkey, signing_root, signed_header.signature)

and
https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.5/specs/phase0/beacon-chain.md#get_domain has

def get_domain(state: BeaconState, domain_type: DomainType, epoch: Epoch=None) -> Domain:
    """
    Return the signature domain (fork version concatenated with domain type) of a message.
    """
    epoch = get_current_epoch(state) if epoch is None else epoch
    fork_version = state.fork.previous_version if epoch < state.fork.epoch else state.fork.current_version
    return compute_domain(domain_type, fork_version, state.genesis_validators_root)

That is, when it's called from verify_execution_payload_header_signature this way, with two arguments, get_domain does not use GENESIS_EPOCH but rather get_current_epoch(state).

The signatures are a function of fork in this case, and that needs to be reflected in this compute_execution_payload_header_signing_root function.


# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.4/specs/_features/eip7732/beacon-chain.md#new-verify_execution_payload_envelope_signature
func compute_execution_payload_envelope_signing_root*(
genesisFork: Fork, genesis_validators_root: Eth2Digest,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also not genesis fork.

https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.5/specs/_features/eip7732/beacon-chain.md#new-verify_execution_payload_envelope_signature reads

def verify_execution_payload_envelope_signature(
        state: BeaconState, signed_envelope: SignedExecutionPayloadEnvelope) -> bool:
    builder = state.validators[signed_envelope.message.builder_index]
    signing_root = compute_signing_root(signed_envelope.message, get_domain(state, DOMAIN_BEACON_BUILDER))
    return bls.Verify(builder.pubkey, signing_root, signed_envelope.signature)

so it's another two-parameter call to get_domain(...), regarding which see https://github.com/status-im/nimbus-eth2/pull/6443/files#r1756088823

compute_signing_root(msg.message, domain)

func get_execution_payload_header_signature*(
genesisFork: Fork, genesis_validators_root: Eth2Digest,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None of these are genesisFork (in get_execution_payload_header_signature, verify_execution_payload_header_signature, compute_execution_payload_envelope_signing_root, etc)

genesisFork: Fork, genesis_validators_root: Eth2Digest,
msg: epbs.SignedExecutionPayloadEnvelope): Eth2Digest =
# So the epoch doesn't matter when calling get_domain
doAssert genesisFork.previous_version == genesisFork.current_version
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assertion will in general not hold true, because not genesis fork. That's basically what it's testing for; there's by definition no previous fork for the genesis fork

state.latest_full_slot = state.slot

if verify:
assert envelope.state_root == hash_tree_root(state)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should use https://nim-lang.org/docs/assertions.html#doAssert.t%2Cuntyped%2Cstring rather than https://nim-lang.org/docs/assertions.html#assert.t%2Cuntyped%2Cstring because the former:

is always turned on regardless of --assertions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants