@@ -72,58 +72,108 @@ func getStandardCheatCodeContract(tracer *cheatCodeTracer) (*CheatCodeContract,
7272 return nil , err
7373 }
7474
75- // Warp: Sets VM timestamp
75+ // Warp: Sets VM timestamp. Note that this _permanently_ updates the block timestamp for the remainder of the
76+ // chain's lifecycle.
7677 contract .addMethod (
7778 "warp" , abi.Arguments {{Type : typeUint256 }}, abi.Arguments {},
7879 func (tracer * cheatCodeTracer , inputs []any ) ([]any , * cheatCodeRawReturnData ) {
79- // Maintain our changes until the transaction exits.
80+ // Capture the original time
8081 originalTime := tracer .chain .pendingBlockContext .Time
8182
82- // Retrieve new timestamp and make sure it is LEQ max value of an uint64
83+ // Retrieve the new timestamp and make sure it is LEQ max value of an uint64
8384 newTime := inputs [0 ].(* big.Int )
8485 if newTime .Cmp (MaxUint64 ) > 0 {
8586 return nil , cheatCodeRevertData ([]byte ("warp: timestamp exceeds max value of type(uint64).max" ))
8687 }
8788
88- // Set the time
89+ // Set the time for the pending block context and the pending block
90+ // The block context will reflect the time change in the current EVM context
91+ // And the pending block time will allow for the new time to reflect
92+ // permanently for the remainder of the chain's existence.
8993 tracer .chain .pendingBlockContext .Time = newTime .Uint64 ()
90- tracer .CurrentCallFrame ().onTopFrameExitRestoreHooks .Push (func () {
91- // Reset the time
92- tracer .chain .pendingBlockContext .Time = originalTime
94+ tracer .chain .pendingBlock .Header .Time = newTime .Uint64 ()
95+
96+ // If the transaction reverts, we will restore the original time
97+ tracer .CurrentCallFrame ().onChainRevertRestoreHooks .Push (func () {
98+ // The warp's effect will naturally revert if the chain reverts. Thus, we only want to handle the
99+ // case if the transaction that called warp reverts (which is why we have the nil checks).
100+ if tracer .chain .pendingBlockContext != nil {
101+ tracer .chain .pendingBlockContext .Time = originalTime
102+ }
103+ if tracer .chain .pendingBlock != nil {
104+ tracer .chain .pendingBlock .Header .Time = originalTime
105+ }
93106 })
94107 return nil , nil
95108 },
96109 )
97110
98- // Roll: Sets VM block number
111+ // Roll: Sets VM block number. Note that this _permanently_ updates the block number for the remainder of the
112+ // chain's lifecycle
99113 contract .addMethod (
100114 "roll" , abi.Arguments {{Type : typeUint256 }}, abi.Arguments {},
101115 func (tracer * cheatCodeTracer , inputs []any ) ([]any , * cheatCodeRawReturnData ) {
102- // Maintain our changes until the transaction exits.
103- original := new (big.Int ).Set (tracer .chain .pendingBlockContext .BlockNumber )
104- tracer .chain .pendingBlockContext .BlockNumber .Set (inputs [0 ].(* big.Int ))
105- tracer .CurrentCallFrame ().onTopFrameExitRestoreHooks .Push (func () {
106- tracer .chain .pendingBlockContext .BlockNumber .Set (original )
116+ // Capture the original block number
117+ originalBlockNumber := tracer .chain .pendingBlockContext .BlockNumber
118+
119+ // Retrieve the new block number
120+ newBlockNumber := inputs [0 ].(* big.Int )
121+
122+ // Set the block number for the pending block context and the pending block
123+ // The block context will reflect the block number change in the current EVM context
124+ // And the pending block number will allow for the number to reflect
125+ // permanently for the remainder of the chain.
126+ tracer .chain .pendingBlockContext .BlockNumber .Set (newBlockNumber )
127+ tracer .chain .pendingBlock .Header .Number .Set (newBlockNumber )
128+
129+ // If the transaction reverts, we will restore the original block number
130+ tracer .CurrentCallFrame ().onChainRevertRestoreHooks .Push (func () {
131+ // The roll's effect will naturally revert if the chain reverts. Thus, we only want to handle the
132+ // case if the transaction that called roll reverts (which is why we have the nil checks).
133+ if tracer .chain .pendingBlockContext != nil {
134+ tracer .chain .pendingBlockContext .BlockNumber .Set (originalBlockNumber )
135+ }
136+ if tracer .chain .pendingBlock != nil {
137+ tracer .chain .pendingBlock .Header .Number .Set (originalBlockNumber )
138+ }
107139 })
140+
108141 return nil , nil
109142 },
110143 )
111144
112- // Fee: Update base fee
145+ // Fee: Update the base bee. Note that this _permanently_ updates the base fee for the remainder of the
146+ // chain's lifecycle
113147 contract .addMethod (
114148 "fee" , abi.Arguments {{Type : typeUint256 }}, abi.Arguments {},
115149 func (tracer * cheatCodeTracer , inputs []any ) ([]any , * cheatCodeRawReturnData ) {
116- // Maintain our changes until the transaction exits.
150+ // Capture the original value
117151 original := new (big.Int ).Set (tracer .chain .pendingBlockContext .BaseFee )
152+
153+ // Update the pending block context and pending block's base fee
154+ // The block context will reflect the base fee change in the current EVM context
155+ // And the pending block will allow for the base fee to reflect
156+ // permanently for the remainder of the chain.
118157 tracer .chain .pendingBlockContext .BaseFee .Set (inputs [0 ].(* big.Int ))
119- tracer .CurrentCallFrame ().onTopFrameExitRestoreHooks .Push (func () {
120- tracer .chain .pendingBlockContext .BaseFee .Set (original )
158+ tracer .chain .pendingBlock .Header .BaseFee .Set (inputs [0 ].(* big.Int ))
159+
160+ // If the transaction reverts, we will restore the original base fee
161+ tracer .CurrentCallFrame ().onChainRevertRestoreHooks .Push (func () {
162+ // The fee's effect will naturally revert if the chain reverts. Thus, we only want to handle the
163+ // case if the transaction that called fee reverts (which is why we have the nil checks).
164+ if tracer .chain .pendingBlockContext != nil {
165+ tracer .chain .pendingBlockContext .BaseFee .Set (original )
166+ }
167+ if tracer .chain .pendingBlock != nil {
168+ tracer .chain .pendingBlock .Header .BaseFee .Set (original )
169+ }
121170 })
122171 return nil , nil
123172 },
124173 )
125174
126175 // Difficulty: Updates difficulty
176+ // TODO: Make changes to difficulty permanent and make it revert for post-Paris EVM versions
127177 contract .addMethod (
128178 "difficulty" , abi.Arguments {{Type : typeUint256 }}, abi.Arguments {},
129179 func (tracer * cheatCodeTracer , inputs []any ) ([]any , * cheatCodeRawReturnData ) {
@@ -141,6 +191,38 @@ func getStandardCheatCodeContract(tracer *cheatCodeTracer) (*CheatCodeContract,
141191 },
142192 )
143193
194+ // TODO: Add prevrandao cheatcode
195+
196+ // Coinbase: Updates the block coinbase. Note that this _permanently_ updates the coinbase for the remainder of the
197+ // chain's lifecycle
198+ contract .addMethod (
199+ "coinbase" , abi.Arguments {{Type : typeAddress }}, abi.Arguments {},
200+ func (tracer * cheatCodeTracer , inputs []any ) ([]any , * cheatCodeRawReturnData ) {
201+ // Capture the original coinbase
202+ original := tracer .chain .pendingBlockContext .Coinbase
203+
204+ // Update the pending block context and the pending block's coinbase
205+ // The block context will reflect the coinbase change in the current EVM context
206+ // And the pending block will allow for the coinbase change to reflect
207+ // permanently for the remainder of the chain.
208+ tracer .chain .pendingBlockContext .Coinbase = inputs [0 ].(common.Address )
209+ tracer .chain .pendingBlock .Header .Coinbase = inputs [0 ].(common.Address )
210+
211+ // If the transaction reverts, we will restore the original base fee
212+ tracer .CurrentCallFrame ().onChainRevertRestoreHooks .Push (func () {
213+ // The coinbase's effect will naturally revert if the chain reverts. Thus, we only want to handle the
214+ // case if the transaction that called coinbase reverts (which is why we have the nil checks).
215+ if tracer .chain .pendingBlockContext != nil {
216+ tracer .chain .pendingBlockContext .Coinbase = original
217+ }
218+ if tracer .chain .pendingBlock != nil {
219+ tracer .chain .pendingBlock .Header .Coinbase = original
220+ }
221+ })
222+ return nil , nil
223+ },
224+ )
225+
144226 // ChainId: Sets VM chain ID
145227 contract .addMethod (
146228 "chainId" , abi.Arguments {{Type : typeUint256 }}, abi.Arguments {},
@@ -224,20 +306,6 @@ func getStandardCheatCodeContract(tracer *cheatCodeTracer) (*CheatCodeContract,
224306 },
225307 )
226308
227- // Coinbase: Sets the block coinbase.
228- contract .addMethod (
229- "coinbase" , abi.Arguments {{Type : typeAddress }}, abi.Arguments {},
230- func (tracer * cheatCodeTracer , inputs []any ) ([]any , * cheatCodeRawReturnData ) {
231- // Maintain our changes until the transaction exits.
232- original := tracer .chain .pendingBlockContext .Coinbase
233- tracer .chain .pendingBlockContext .Coinbase = inputs [0 ].(common.Address )
234- tracer .CurrentCallFrame ().onTopFrameExitRestoreHooks .Push (func () {
235- tracer .chain .pendingBlockContext .Coinbase = original
236- })
237- return nil , nil
238- },
239- )
240-
241309 // Prank: Sets the msg.sender within the next EVM call scope created by the caller.
242310 contract .addMethod (
243311 "prank" , abi.Arguments {{Type : typeAddress }}, abi.Arguments {},
0 commit comments