-
Notifications
You must be signed in to change notification settings - Fork 142
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
Move atomic sync #723
base: seperate-atomic-pkg-base
Are you sure you want to change the base?
Move atomic sync #723
Conversation
@@ -74,13 +79,13 @@ type StateSyncClientConfig struct { | |||
type stateSyncerClient struct { | |||
*StateSyncClientConfig | |||
|
|||
resumableSummary message.SyncSummary | |||
resumableSummary message.Syncable |
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.
this can be nil and we do check it
|
||
cancel context.CancelFunc | ||
wg sync.WaitGroup | ||
|
||
// State Sync results | ||
syncSummary message.SyncSummary | ||
syncSummary message.Syncable |
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.
this can be nil, but we never use it when it's nil.
var Codec codec.Manager | ||
var ( | ||
Codec codec.Manager | ||
// TODO: Remove this once we have a better way to register types (i.e use a different codec version or use build flags) |
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 can move init to a function like (Initialize) and call in vm.Initialize like Codec.Initialize(SyncSummaryType)
, but then tests should be doing the same thing everytime. But it might be the only way once we merge subnet-evm since two VMs should be using two different codecs since subnet-evm do not have atomic types (and thus codec has different order of type IDs).
Signed-off-by: Ceyhun Onur <[email protected]>
Signed-off-by: Ceyhun Onur <[email protected]>
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.
Nice tidying up 😉 And thanks for that thick detailed PR body 👍
I just left a few comments, mostly non-important things to be fair. Most of them you can apply as suggestions directly or discard them in case we should keep similar code with subnet-evm at this time.
log.Info("atomic tx: sync starting", "root", atomicSyncSummary) | ||
atomicSyncer, err := a.backend.Syncer(client, atomicSyncSummary.AtomicRoot, atomicSyncSummary.BlockNumber, a.stateSyncRequestSize) | ||
if err != nil { | ||
return err |
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.
return err | |
return fmt.Error("creating syncer: %s", err) |
PS: I also used to (like you I think?) wrap all the errors with %w
so the callers can use errors.Is
if they want to, until very recently. The problem is you then expose API that might not even come from your own package (Arran pointed me to this), so having them as dumb strings %s
is better, unless you actually need to check the errors programmatically.
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.
but isn't that the case if we use %s
in any of chained (wrapped) errs, then we would lose all the ability to check with errors.Is
?
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.
IMO:
- There's no need to wrap all errors. It seems quite cumbersome to wrap every single error and in shared codebase with geth is doesn't seem feasible. I'm not sold on the advantages.
- Seems best to wrap the error (%w) for consistency with the case that doesn't wrap the error (return err)
Given shared code, I suggest we follow the current convention of adding a wrapped error when the context has proven useful for debugging.
Additionally the geth codebase use a mix of panics, returning wrapped & unwrapped errs, and log.Crit, so I don't think this is an issue we need to address now.
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.
There's no need to wrap all errors. It seems quite cumbersome to wrap every single error
Additionally the geth codebase use a mix of panics, returning wrapped & unwrapped errs, and log.Crit, so I don't think this is an issue we need to address now.
I disagree, wrapping errors helps debugging or the user understand an error message. For example, I saw recently avalanche-cli complain about some obscure error, which, as a user, was very confusing, and, as someone who looked in the code, I couldn't really figure out where it was coming from either. Of course we don't want to modify geth code, but I don't think we should not make our part of the code better (unless geth checks the error with ==
, which really it shouldn't - I might PR this to geth)
Seems best to wrap the error (%w) for consistency with the case that doesn't wrap the error (return err)
Actually I think geth do check errors directly with ==
whereas wrapping errors with %w
only works with errors.Is
, not ==
, so two different operations, although errors.Is
works with unwrapped (sentinel) errors. Really geth should always use errors.Is
(works for both cases) and not ==
to check errors.
|
||
"github.com/ava-labs/avalanchego/snow/engine/snowman/block" | ||
|
||
"github.com/ava-labs/coreth/core" |
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 shouldn't import core in the atomic package this will couple it to libevm bindings again.
IMO we can have a pacakge like atomic/sync.
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.
See #723 (comment)
stateSyncRequestSize uint16 | ||
} | ||
|
||
func NewAtomicSyncExtender(backend state.AtomicBackend, stateSyncRequestSize uint16) *AtomicSyncExtender { |
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.
nit you could define an interface AtomicBackend
in this package instead of using state.AtomicBackend
so that:
- reduces dependency on
state
package - narrower interface: you only need the Root method here
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 moved them to interfaces pkg.
var _ sync.SummaryProvider = &AtomicSyncProvider{} | ||
|
||
type AtomicSyncProvider struct { | ||
chain *core.BlockChain |
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.
you could define an interface Chain
for this chain
field with only GetBlockByNumber
and HasState
, so that it removes the dependency on the core package.
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.
unfortunately it goes deeper than that as GetBlockByNumber
returns types.Block
so we end-up importing the core package anyway. We can create an adapter and wrap the passed blockchain here, but I think having a separate pkg for sync should be good enough.
} | ||
} | ||
|
||
func (a *AtomicSyncExtender) Sync(ctx context.Context, client syncclient.Client, verDB *versiondb.Database, syncSummary message.Syncable) 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.
client syncclient.Client
can be the narrower interface client syncclient.LeafClient
(Extender
interface needs that update as well).
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.
done
a.stateSyncRequestSize, | ||
) | ||
if err != nil { | ||
return err |
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.
nit
return err | |
return fmt.Errorf("failed to create atomic syncer: %w", err) |
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.
done
return nil, fmt.Errorf("atomic trie root not found for height (%d)", height) | ||
} | ||
|
||
blk := a.chain.GetBlockByNumber(height) |
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.
nit perhaps (makes more sense to me I'd say)
- alias
block
tosnowblock
- then rename
blk
toblock
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.
seems weird to rename a package import to avoid namespace collision with a local variable. (seems one would usually rename a local variable to avoid aliasing an imported package)
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.
let's keep this as it is.
// BlockSyncSummary provides the information necessary to sync a node starting | ||
// at the given block. | ||
type SyncSummary struct { | ||
type BlockSyncSummary struct { |
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.
did we need to rename SyncSummary
to BlockSyncSummary
? 🤔
It seems like unneeded changes, unless there is a reason?
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.
This is to distinguish between AtomicBlockSyncSummary
return nil, fmt.Errorf("atomic trie root not found for height (%d)", height) | ||
} | ||
|
||
blk := a.chain.GetBlockByNumber(height) |
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.
seems weird to rename a package import to avoid namespace collision with a local variable. (seems one would usually rename a local variable to avoid aliasing an imported package)
plugin/evm/syncervm_test.go
Outdated
@@ -56,7 +57,7 @@ func TestSkipStateSync(t *testing.T) { | |||
stateSyncMinBlocks: 300, // must be greater than [syncableInterval] to skip sync | |||
syncMode: block.StateSyncSkipped, | |||
} | |||
vmSetup := createSyncServerAndClientVMs(t, test, StateSyncParentsToFetch) | |||
vmSetup := createSyncServerAndClientVMs(t, test, vmsync.StateSyncParentsToFetch) |
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.
seems we can rename these to drop the StateSync prefix with this refactor
plugin/evm/vm.go
Outdated
vmsync.StateSyncServer | ||
vmsync.StateSyncClient |
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.
seems these can also be renamed to vmsync.Server
/ vmsync.Client
} | ||
|
||
func init() { | ||
message.SyncSummaryType = &AtomicBlockSyncSummary{} |
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.
how does this work in conjunction with the call to .RegisterType(SyncSummaryType)?
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.
this is indeed an ugly assumption that assumes var is called before init blocks.
plugin/evm/sync/syncervm_client.go
Outdated
if err := client.ExtraSyncer.OnFinishBeforeCommit(client.LastAcceptedHeight, client.syncSummary); err != nil { | ||
return err | ||
} |
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.
optional: maybe move this out of updateVMMarkers so OnFinishBeforeCommit/OnFinishAfterCommit are closer to each other.
Why this should be merged
Decouples atomic logic from syncervm server/client to atomic pkg.
How this works
This pull request introduces a new atomic sync mechanism for the EVM plugin. The changes include the creation of new types and interfaces for atomic sync summaries, along with the implementation of the sync process. The most important changes are summarized below:
Introduction of Atomic Sync Mechanism:
plugin/evm/atomic/atomic_sync_extender.go
: Added theatomicSyncExtender
type and its methods to handle the synchronization process, includingSync
,OnFinishBeforeCommit
, andOnFinishAfterCommit
.plugin/evm/atomic/atomic_sync_provider.go
: Introduced theatomicSyncProvider
type to provide state summaries at specific heights.plugin/evm/atomic/syncable.go
: Defined theAtomicBlockSyncSummary
type and related functions to parse and create sync summaries.Refactoring and Code Organization:
plugin/evm/message/codec.go
: Updated the codec manager to register the new sync summary type and introduced a variable to hold the sync summary type. [1] [2]plugin/evm/message/syncable.go
: Refactored theBlockSyncSummary
to implement theSyncable
interface and added a parser for sync summaries.File and Type Renaming:
plugin/evm/sync/syncervm_client.go
: Renamed fromplugin/evm/syncervm_client.go
and updated to use the newSyncable
interface andatomicSyncExtender
for the sync process. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12]How this was tested
Existing UTs should cover
Need to be documented?
No
Need to update RELEASES.md?
No