Skip to content

fix: address race condition during EuclidV2 header chain verification #1186

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 29 additions & 4 deletions consensus/wrapper/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,31 @@ func (ue *UpgradableEngine) VerifyHeader(chain consensus.ChainHeaderReader, head
return ue.chooseEngine(header.Time).VerifyHeader(chain, header, seal)
}

func waitForHeader(chain consensus.ChainHeaderReader, header *types.Header) {
hash, number := header.Hash(), header.Number.Uint64()

// poll every 2 seconds, should succeed after a few tries
ticker := time.NewTicker(2 * time.Second)
defer ticker.Stop()

// we give up after 2 minutes
timeout := time.After(120 * time.Second)

for {
select {
case <-ticker.C:
// try reading from chain, if the header is present then we are ready
if h := chain.GetHeader(hash, number); h != nil {
return
}

case <-timeout:
log.Warn("Unable to find last pre-EuclidV2 header in chain", "hash", hash.Hex(), "number", number)
return
}
}
}

// VerifyHeaders verifies a batch of headers concurrently. In our use-case,
// headers can only be all system, all clique, or start with clique and then switch once to system.
func (ue *UpgradableEngine) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) {
Expand Down Expand Up @@ -124,10 +149,10 @@ func (ue *UpgradableEngine) VerifyHeaders(chain consensus.ChainHeaderReader, hea
}
}

// Not sure why we need this here, but without this we get err="unknown ancestor"
// at the 1st Euclid block. It seems that `VerifyHeaders` start processing the next
// header before the previous one was written into `chain`.
time.Sleep(2 * time.Second)
// `VerifyHeader` will try to call `chain.GetHeader`, which will race with `InsertHeaderChain`.
// This might result in "unknown ancestor" header validation error.
// This should be temporary, so we solve this by waiting here.
waitForHeader(chain, cliqueHeaders[len(cliqueHeaders)-1])

// Verify system contract headers.
log.Info("Start EuclidV2 transition verification in SystemContract section", "startBlockNumber", systemHeaders[0].Number, "endBlockNumber", systemHeaders[len(systemHeaders)-1].Number)
Expand Down
2 changes: 1 addition & 1 deletion params/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
const (
VersionMajor = 5 // Major version component of the current release
VersionMinor = 8 // Minor version component of the current release
VersionPatch = 45 // Patch version component of the current release
VersionPatch = 46 // Patch version component of the current release
VersionMeta = "mainnet" // Version metadata to append to the version string
)

Expand Down
Loading