@@ -39,8 +39,8 @@ func NewUpgradableEngine(isUpgraded func(uint64) bool, clique consensus.Engine,
39
39
}
40
40
41
41
// 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 ) {
44
44
return ue .system
45
45
}
46
46
return ue .clique
@@ -51,12 +51,12 @@ func (ue *UpgradableEngine) chooseEngine(header *types.Header) consensus.Engine
51
51
52
52
// Author returns the author of the block based on the header.
53
53
func (ue * UpgradableEngine ) Author (header * types.Header ) (common.Address , error ) {
54
- return ue .chooseEngine (header ).Author (header )
54
+ return ue .chooseEngine (header . Time ).Author (header )
55
55
}
56
56
57
57
// VerifyHeader checks whether a header conforms to the consensus rules of the engine.
58
58
func (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 )
60
60
}
61
61
62
62
// VerifyHeaders verifies a batch of headers concurrently. In our use-case,
@@ -72,8 +72,8 @@ func (ue *UpgradableEngine) VerifyHeaders(chain consensus.ChainHeaderReader, hea
72
72
}
73
73
74
74
// 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 )
77
77
78
78
// If the first header is system, then all headers must be system.
79
79
if firstEngine == ue .system {
@@ -89,7 +89,7 @@ func (ue *UpgradableEngine) VerifyHeaders(chain consensus.ChainHeaderReader, hea
89
89
// a single switchover, find the first header that uses system.
90
90
splitIndex := 0
91
91
for i , header := range headers {
92
- if ue .chooseEngine (header ) == ue .system {
92
+ if ue .chooseEngine (header . Time ) == ue .system {
93
93
splitIndex = i
94
94
break
95
95
}
@@ -151,34 +151,77 @@ func (ue *UpgradableEngine) VerifyHeaders(chain consensus.ChainHeaderReader, hea
151
151
return abort , results
152
152
}
153
153
154
+ func (ue * UpgradableEngine ) CalcTimestamp (parent * types.Header ) uint64 {
155
+ panic ("Called CalcTimestamp on UpgradableEngine, not implemented" )
156
+ }
157
+
154
158
// 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
+ }
157
200
}
158
201
159
202
// Seal instructs the engine to start sealing a block.
160
203
func (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 )
162
205
}
163
206
164
207
// CalcDifficulty calculates the block difficulty if applicable.
165
208
func (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 )
167
210
}
168
211
169
212
// Finalize finalizes the block, applying any post-transaction rules.
170
213
func (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 )
172
215
}
173
216
174
217
// FinalizeAndAssemble finalizes and assembles a new block.
175
218
func (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 )
177
220
}
178
221
179
222
// VerifyUncles verifies that no uncles are attached to the block.
180
223
func (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 )
182
225
}
183
226
184
227
// APIs returns any RPC APIs exposed by the consensus engine.
@@ -203,7 +246,7 @@ func (ue *UpgradableEngine) Close() error {
203
246
204
247
// SealHash returns the hash of a block prior to it being sealed.
205
248
func (ue * UpgradableEngine ) SealHash (header * types.Header ) common.Hash {
206
- return ue .chooseEngine (header ).SealHash (header )
249
+ return ue .chooseEngine (header . Time ).SealHash (header )
207
250
}
208
251
209
252
// Authorize injects a private key into the consensus engine to mint new blocks
0 commit comments