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

Support for syncing on mergemock #3174

Merged
merged 41 commits into from
Dec 29, 2021
Merged

Support for syncing on mergemock #3174

merged 41 commits into from
Dec 29, 2021

Conversation

Giulio2002
Copy link
Contributor

@Giulio2002 Giulio2002 commented Dec 26, 2021

Things Added

  • Code for Block Proposing
  • Validators can now be ran on Erigon
  • Private testnet with proof-of-stake enabled can be ran on Erigon
  • mergemock can be ran on Erigon
  • All test vectors from EF pass successfully

Prerequisite

Above PRs must be merged for this PR to not be a draft @AskAlexSharov

Things missing before moving to M2 Kinstugi Milestones:

  • Disable P2P Gossip accordingly to spec
  • EIP-2124

@Giulio2002 Giulio2002 marked this pull request as draft December 26, 2021 19:02
@Giulio2002
Copy link
Contributor Author

More things to add: if ran against mergemock VerifyHeader could fail, probably a bug in mergemock, for now i commented the verifyHeader statement. other thing to say, if we are on the tip of the chain and receive the new head, i made it so we process the bodies in stage headers, i will change it in a next PR, this one is too big already honestly.

@Giulio2002 Giulio2002 marked this pull request as ready for review December 26, 2021 21:18
@Giulio2002
Copy link
Contributor Author

We use it to communicate the mined block to ForkchoiceUpdated, so that we keep mining separate from ethbackend

@yperbasis
Copy link
Member

We use it to communicate the mined block to ForkchoiceUpdated, so that we keep mining separate from ethbackend

But where's the code that reads MiningFinishCfg.assembledBlock?

@Giulio2002
Copy link
Contributor Author

here https://github.com/ledgerwatch/erigon/blob/45cfc7ed83aafd4d55f4a0c728fed0674aa5ae79/ethdb/privateapi/ethbackend.go#L308 s.assembledBlock is the same pointer as in the mining staged sync

@yperbasis
Copy link
Member

https://github.com/ledgerwatch/erigon/blob/45cfc7ed83aafd4d55f4a0c728fed0674aa5ae79/ethdb/privateapi/ethbackend.go#L308

s.assembledBlock is the same pointer as in the mining staged sync

Hmm. I'm afraid I'm still not following. Where is the code that ensures that MiningFinishCfg.assembledBlock is the same as EthBackendServer.assembledBlock?

@Giulio2002
Copy link
Contributor Author

@yperbasis
Copy link
Member

It is the same pointer

Ah, OK, I see. The problem is that you need a syncronization mechanism to prevent data races since the data will be accessed from multiple goroutines. You should use something like atomic.Value (or a channel or a mutex perhaps).

@yperbasis
Copy link
Member

Something like "Concurrency in Go" by Katherine Cox–buday is a nice read :)

) error {
atomic.StoreUint32(cfg.waitingPosHeaders, 1)
// We need to have another write transaction for the miner in case we want to validate.
Copy link
Member

Choose a reason for hiding this comment

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

Not sure I'm following. Why do you commit the transaction?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

we are closing it, in case we receive the request to mine. Mining stages uses a write transaction so we would stall when trying to propose new blocks

Copy link
Member

@yperbasis yperbasis Dec 28, 2021

Choose a reason for hiding this comment

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

Hmm. My gut feeling is that the transaction commitment here might be problematic. I don't understand the current interplay between waiting for PoS blocks and the mining. Probably need to pick up @AskAlexSharov brain for that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I do not think it is problematic, if any error occur we rollback them, so if the tx has not been killed and has been kept by another stage it should not give problems. if any stage does not rollback on error then the issue is not in the scope of stage headers. I can explain the interplay, mining stages uses a write transaction and block proposing happens only if we are waiting the beacon chain, thus when mining is requested the stagedsync must be in stage headers waiting for payloads. now if we did not close it prior waiting, the mining stage will never start unless we close the write transaction in stage headers. because you cannot have more than 2 write transactions on MDBX.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note also that external transactions are usually used for unit tests and not for production

Copy link
Member

Choose a reason for hiding this comment

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

And when the Beacon node sends us a engine_forkchoiceupdatedv1 request with a payload, ethbackend should send a message to SkipCycleHack to interrupt the wait in the header stage.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

okay, so to answer all the points:

  • Beacon chain calls are synchronous
  • if external transactions are used in production then ending stage headers simply wont't be enough
  • I noticed that there is an actual benefit of doing how i did it as of now, before we mined block every 3 seconds on a goroutine constantly, now we can do the same without having a goroutine constantly on and only when requested.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it makes more sense logically to do it like this, also tests are passing so it should not break any other component

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, must just wait until we timeout

Copy link
Member

Choose a reason for hiding this comment

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

The thing is that Beacon mining ("payload build process") is supposed to be asynchronous. engine_forkchoiceUpdatedV1 with payload should only initiate the mining, not to wait for its completion. So IMHO more work is still required.

But this PR is too big already. In order to make progress, I suggest the following:

  1. Leave only a rudimentary block build process in this PR, without any transactions (probably w/o correct state root either). Then we continue the work on proper PoS mining with transactions and everything in a subsequent PR.
  2. Restore the useExternalTx logic in HeaderPoS and don't do this tx.Commit hack.

eth/backend.go Outdated
@@ -404,9 +404,29 @@ func New(stack *node.Node, config *ethconfig.Config, logger log.Logger) (*Ethere
if casted, ok := backend.engine.(*ethash.Ethash); ok {
ethashApi = casted.APIs(nil)[1].Service.(*ethash.API)
}
atomic.StoreUint32(&backend.waitingForPOSHeaders, 0)
atomic.StoreUint32(&backend.waitingForBeaconChain, 0)
startAssembleFunc := func(timestamp uint64, random common.Hash, suggestedFeeRecipient common.Address) (types.Block, error) {
Copy link
Member

Choose a reason for hiding this comment

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

We should not perform complete mining here, only to initiate it. Per the spec: "if payloadAttributes is not null and the client is not SYNCING, and MUST begin a payload build process building on top of forkchoiceState.headBlockHash". And the build process should start concurrently and last for up to 12 seconds. See https://github.com/ethereum/execution-apis/blob/v1.0.0-alpha.5/src/engine/specification.md#payload-build-process

Currently startAssembleFunc confusingly not only starts the build process, but waits for it to finish.

@Giulio2002 Giulio2002 changed the title Added block proposal to Proof-of-stake. Support for syncing on mergemock Dec 29, 2021
return nil, err
}

if atomic.LoadUint32(s.waitingForBeaconChain) == 0 || headHeader == nil {
Copy link
Member

Choose a reason for hiding this comment

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

The previous check parent != rawdb.ReadHeadBlockHash(tx) is better since we might have the header in the DB but be on a different fork.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

we are reading the header by hash, which means it looks into blockhashes which does not do only canonical headers

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, that's my point. When our latest canonical header doesn't match headBlockHash, we should return "SYNCING" status and initiate a re-org.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

enrique will add it

@Giulio2002 Giulio2002 merged commit 864b744 into devel Dec 29, 2021
@Giulio2002 Giulio2002 deleted the mining-pos branch December 29, 2021 16:25
@VBulikov VBulikov mentioned this pull request Feb 5, 2025
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.

5 participants