@@ -39,8 +39,8 @@ func NewUpgradableEngine(isUpgraded func(uint64) bool, clique consensus.Engine,
3939}
4040
4141// chooseEngine returns the appropriate consensus engine based on the header's timestamp.
42- func (ue * UpgradableEngine ) chooseEngine (header * types. Header ) consensus.Engine {
43- if ue .isUpgraded (header . Time ) {
42+ func (ue * UpgradableEngine ) chooseEngine (timestamp uint64 ) consensus.Engine {
43+ if ue .isUpgraded (timestamp ) {
4444 return ue .system
4545 }
4646 return ue .clique
@@ -51,12 +51,12 @@ func (ue *UpgradableEngine) chooseEngine(header *types.Header) consensus.Engine
5151
5252// Author returns the author of the block based on the header.
5353func (ue * UpgradableEngine ) Author (header * types.Header ) (common.Address , error ) {
54- return ue .chooseEngine (header ).Author (header )
54+ return ue .chooseEngine (header . Time ).Author (header )
5555}
5656
5757// VerifyHeader checks whether a header conforms to the consensus rules of the engine.
5858func (ue * UpgradableEngine ) VerifyHeader (chain consensus.ChainHeaderReader , header * types.Header , seal bool ) error {
59- return ue .chooseEngine (header ).VerifyHeader (chain , header , seal )
59+ return ue .chooseEngine (header . Time ).VerifyHeader (chain , header , seal )
6060}
6161
6262// VerifyHeaders verifies a batch of headers concurrently. In our use-case,
@@ -72,8 +72,8 @@ func (ue *UpgradableEngine) VerifyHeaders(chain consensus.ChainHeaderReader, hea
7272 }
7373
7474 // Choose engine for the first and last header.
75- firstEngine := ue .chooseEngine (headers [0 ])
76- lastEngine := ue .chooseEngine (headers [len (headers )- 1 ])
75+ firstEngine := ue .chooseEngine (headers [0 ]. Time )
76+ lastEngine := ue .chooseEngine (headers [len (headers )- 1 ]. Time )
7777
7878 // If the first header is system, then all headers must be system.
7979 if firstEngine == ue .system {
@@ -89,7 +89,7 @@ func (ue *UpgradableEngine) VerifyHeaders(chain consensus.ChainHeaderReader, hea
8989 // a single switchover, find the first header that uses system.
9090 splitIndex := 0
9191 for i , header := range headers {
92- if ue .chooseEngine (header ) == ue .system {
92+ if ue .chooseEngine (header . Time ) == ue .system {
9393 splitIndex = i
9494 break
9595 }
@@ -151,34 +151,77 @@ func (ue *UpgradableEngine) VerifyHeaders(chain consensus.ChainHeaderReader, hea
151151 return abort , results
152152}
153153
154+ func (ue * UpgradableEngine ) CalcTimestamp (parent * types.Header ) uint64 {
155+ panic ("Called CalcTimestamp on UpgradableEngine, not implemented" )
156+ }
157+
154158// Prepare prepares a block header for sealing.
155- func (ue * UpgradableEngine ) Prepare (chain consensus.ChainHeaderReader , header * types.Header ) error {
156- return ue .chooseEngine (header ).Prepare (chain , header )
159+ func (ue * UpgradableEngine ) Prepare (chain consensus.ChainHeaderReader , header * types.Header , timeOverride * uint64 ) error {
160+ // Override provided => select engine based on override timestamp.
161+ if timeOverride != nil {
162+ return ue .chooseEngine (* timeOverride ).Prepare (chain , header , timeOverride )
163+ }
164+
165+ parent := chain .GetHeader (header .ParentHash , header .Number .Uint64 ()- 1 )
166+ if parent == nil {
167+ return consensus .ErrUnknownAncestor
168+ }
169+
170+ // Check if parent is pre- or post-EuclidV2.
171+ if ue .chooseEngine (parent .Time ) == ue .clique {
172+ // This is either a normal Clique block, or the EuclidV2 transition block.
173+
174+ time := ue .clique .CalcTimestamp (parent )
175+
176+ if ue .chooseEngine (time ) == ue .clique {
177+ // We're still in Clique mode.
178+ // Note: We must provide timestamp override to avoid the edge case
179+ // where we slip over into EuclidV2 in this next call.
180+ return ue .clique .Prepare (chain , header , & time )
181+ } else {
182+ // This is the EuclidV2 transition block.
183+ return ue .system .Prepare (chain , header , & time )
184+ }
185+ } else {
186+ // We are already post EuclidV2, in SystemContract mode.
187+
188+ time := ue .system .CalcTimestamp (parent )
189+
190+ if ue .chooseEngine (time ) == ue .clique {
191+ // Somehow we slipped back to Clique, override with a known post-EuclidV2 timestamp.
192+ // Note: This should not happen in practice.
193+ log .Error ("Parent is post-EuclidV2 but SystemContract set pre-EuclidV2 timestamp, overriding" , "blockNumber" , header .Number , "parentTime" , parent .Time , "systemContractTime" , time )
194+ return ue .system .Prepare (chain , header , & parent .Time )
195+ } else {
196+ // We are already in SystemContract mode.
197+ return ue .system .Prepare (chain , header , & time )
198+ }
199+ }
157200}
158201
159202// Seal instructs the engine to start sealing a block.
160203func (ue * UpgradableEngine ) Seal (chain consensus.ChainHeaderReader , block * types.Block , results chan <- * types.Block , stop <- chan struct {}) error {
161- return ue .chooseEngine (block .Header ()).Seal (chain , block , results , stop )
204+ return ue .chooseEngine (block .Time ()).Seal (chain , block , results , stop )
162205}
163206
164207// CalcDifficulty calculates the block difficulty if applicable.
165208func (ue * UpgradableEngine ) CalcDifficulty (chain consensus.ChainHeaderReader , time uint64 , parent * types.Header ) * big.Int {
166- return ue .chooseEngine (parent ).CalcDifficulty (chain , time , parent )
209+ return ue .chooseEngine (parent . Time ).CalcDifficulty (chain , time , parent )
167210}
168211
169212// Finalize finalizes the block, applying any post-transaction rules.
170213func (ue * UpgradableEngine ) Finalize (chain consensus.ChainHeaderReader , header * types.Header , state * state.StateDB , txs []* types.Transaction , uncles []* types.Header ) {
171- ue .chooseEngine (header ).Finalize (chain , header , state , txs , uncles )
214+ ue .chooseEngine (header . Time ).Finalize (chain , header , state , txs , uncles )
172215}
173216
174217// FinalizeAndAssemble finalizes and assembles a new block.
175218func (ue * UpgradableEngine ) FinalizeAndAssemble (chain consensus.ChainHeaderReader , header * types.Header , state * state.StateDB , txs []* types.Transaction , uncles []* types.Header , receipts []* types.Receipt ) (* types.Block , error ) {
176- return ue .chooseEngine (header ).FinalizeAndAssemble (chain , header , state , txs , uncles , receipts )
219+ return ue .chooseEngine (header . Time ).FinalizeAndAssemble (chain , header , state , txs , uncles , receipts )
177220}
178221
179222// VerifyUncles verifies that no uncles are attached to the block.
180223func (ue * UpgradableEngine ) VerifyUncles (chain consensus.ChainReader , block * types.Block ) error {
181- return ue .chooseEngine (block .Header ()).VerifyUncles (chain , block )
224+ return ue .chooseEngine (block .Time ()).VerifyUncles (chain , block )
182225}
183226
184227// APIs returns any RPC APIs exposed by the consensus engine.
@@ -203,7 +246,7 @@ func (ue *UpgradableEngine) Close() error {
203246
204247// SealHash returns the hash of a block prior to it being sealed.
205248func (ue * UpgradableEngine ) SealHash (header * types.Header ) common.Hash {
206- return ue .chooseEngine (header ).SealHash (header )
249+ return ue .chooseEngine (header . Time ).SealHash (header )
207250}
208251
209252// Authorize injects a private key into the consensus engine to mint new blocks
0 commit comments