@@ -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