-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Conversation
More things to add: if ran against |
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 |
here https://github.com/ledgerwatch/erigon/blob/45cfc7ed83aafd4d55f4a0c728fed0674aa5ae79/ethdb/privateapi/ethbackend.go#L308 |
Hmm. I'm afraid I'm still not following. Where is the code that ensures that |
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 |
Something like "Concurrency in Go" by Katherine Cox–buday is a nice read :) |
eth/stagedsync/stage_headers.go
Outdated
) error { | ||
atomic.StoreUint32(cfg.waitingPosHeaders, 1) | ||
// We need to have another write transaction for the miner in case we want to validate. |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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:
- 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.
- Restore the
useExternalTx
logic inHeaderPoS
and don't do thistx.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) { |
There was a problem hiding this comment.
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.
return nil, err | ||
} | ||
|
||
if atomic.LoadUint32(s.waitingForBeaconChain) == 0 || headHeader == nil { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
enrique will add it
Things Added
mergemock
can be ran on ErigonPrerequisite
Above PRs must be merged for this PR to not be a draft @AskAlexSharov
Things missing before moving to M2 Kinstugi Milestones: