-
Notifications
You must be signed in to change notification settings - Fork 16
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
feat(sync): Implement a subjectiveHead atomic pointer on the node to use #108
base: main
Are you sure you want to change the base?
Conversation
c9352b5
to
bcc80f8
Compare
Codecov Report
@@ Coverage Diff @@
## main #108 +/- ##
==========================================
+ Coverage 69.09% 69.25% +0.15%
==========================================
Files 37 37
Lines 2938 2979 +41
==========================================
+ Hits 2030 2063 +33
- Misses 758 768 +10
+ Partials 150 148 -2
|
@@ -145,8 +161,12 @@ func (s *Syncer[H]) incomingNetworkHead(ctx context.Context, head H) error { | |||
} | |||
|
|||
// TODO(@Wondertan): | |||
// Implement setSyncTarget and use it for soft failures | |||
s.setSubjectiveHead(ctx, head) | |||
// Implement setSyncTarget and use it for soft failures // TODO @renaynay <-can remove this comment? |
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.
TODO @liamsi ask rene and hlib if these two todos can be removed now? 😅
// this sleep is necessary to allow the syncer to trigger a job | ||
// as calling SyncWait prematurely may falsely return without error | ||
// as the syncer has not yet registered a sync job. | ||
//time.Sleep(time.Millisecond * 100) |
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.
can this be removed?
headertest/dummy_header.go
Outdated
|
||
func (edv ErrDummyVerify) Error() string { | ||
return edv.Reason | ||
} | ||
|
||
type DummyHeader struct { | ||
Chainid string | ||
PreviousHash header.Hash | ||
HeightI uint64 | ||
Timestamp time.Time | ||
|
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.
sync/sync.go
Outdated
// if there's no subjective head stored, syncer has already applied the | ||
// subjective head to the store and the syncer has passed it | ||
if sbjHead != nil { | ||
sh := *sbjHead |
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.
why do you need to deref here? Can't you do it on sbjHead def or cast? either way, please do it on line 333 if possible
sync/sync.go
Outdated
if len(headers) == 0 { | ||
s.metrics.recordTotalSynced(totalHeaders) | ||
return 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.
Is this necessary? I don't know why we can't just leave it how it was
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.
Looks good. Still trying to wrap my head around how the mechanism works
sync/fork_test/fork.go
Outdated
// headers between its storeHead --> subjectiveHead. | ||
type eclipsedExchange struct { | ||
trustedPeer header.Store[*headertest.DummyHeader] | ||
eclipsedExchange header.Store[*headertest.DummyHeader] |
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: keep it consistent with trustedPeer
so we understand there are two different peers
eclipsedExchange header.Store[*headertest.DummyHeader] | |
eclipsedPeer header.Store[*headertest.DummyHeader] |
cmd.Stdout = os.Stderr | ||
cmd.Stderr = os.Stderr | ||
err = cmd.Run() | ||
require.Error(t, 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.
Do you want to make a specific assertion to the error that is generated
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 assertion is below
require.NoError(t, err) | ||
|
||
cmd := exec.Command("go", "run", path) | ||
cmd.Stdout = os.Stderr |
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.
Is it important to catch stdout?
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 to be able to catch the output, but not important
@@ -322,13 +331,44 @@ func (s *Syncer[H]) requestHeaders( | |||
|
|||
// storeHeaders updates store with new headers and updates current syncStore's Head. | |||
func (s *Syncer[H]) storeHeaders(ctx context.Context, headers ...H) 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.
Why is this check done in storeHeaders
? I would have thought this would happen during verification (that we check if it's the height of the subjective head and compare the hashed)
func TestForkFollowingPrevention(t *testing.T) { | ||
path, err := filepath.Abs("./fork_test/fork.go") | ||
require.NoError(t, err) | ||
|
||
cmd := exec.Command("go", "run", path) | ||
cmd.Stdout = os.Stderr |
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.
[complement]
This is smart, and I like it.
headers = headers[segmentSize:] | ||
|
||
err := s.store.Append(ctx, mustApplySegment...) | ||
if err != 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.
[blocking]
This must be a verification error only.
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 agree and also would prefer if we could also assess whether it failed specifically on the height sbjHead-1 against sbjHead
@@ -145,8 +161,12 @@ func (s *Syncer[H]) incomingNetworkHead(ctx context.Context, head H) error { | |||
} | |||
|
|||
// TODO(@Wondertan): | |||
// Implement setSyncTarget and use it for soft failures | |||
s.setSubjectiveHead(ctx, head) | |||
// Implement setSyncTarget and use it for soft failures // TODO @renaynay <-can remove this comment? |
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.
[discussion]
We can keep it until we make setSyncTarget method
sync/sync.go
Outdated
var sbjHeadHeight uint64 | ||
sbjHead := *s.sbjHead.Load() | ||
// if there's no subjective head stored, syncer has already applied the | ||
// subjective head to the store and the syncer has passed it | ||
if !sbjHead.IsZero() { | ||
sbjHeadHeight = sbjHead.Height() | ||
// sanity check the height to check whether it's within the range | ||
if sbjHeadHeight < headers[0].Height() || sbjHeadHeight > headers[len(headers)-1].Height() { | ||
sbjHeadHeight = 0 | ||
} | ||
} | ||
|
||
// if the header is within range, create a segment that *must* be applied | ||
// such that the syncer fails if the subjective head cannot be applied | ||
if sbjHeadHeight != 0 { | ||
segmentSize := sbjHeadHeight - headers[0].Height() + 1 | ||
mustApplySegment := make([]H, segmentSize) | ||
copy(mustApplySegment, headers[:segmentSize]) | ||
headers = headers[segmentSize:] | ||
|
||
err := s.store.Append(ctx, mustApplySegment...) | ||
if err != nil { | ||
log.Fatal(fmt.Errorf("failed to apply trusted head at height %d to synced chain segment, "+ | ||
"potentially following fork: %w", sbjHeadHeight, err)) | ||
} | ||
// if success, then clear subjective head as it's already applied as the store head | ||
s.sbjHead.Store(new(H)) | ||
} |
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.
[suggestion]
Separate this code block with {
and }
and add a TODO pointing to backwards sync issue
303940d
to
a343118
Compare
Something is borked with sync. |
as fork-following prevention
… the syncer crashes if it detects that it has been following a fork
a6716a0
to
91d975a
Compare
Nvm bug was in main |
Resolves #99