def mine(self, blocks: int = 1, timestamp: int = None, timedelta: int = None) -> int: """ Increase the block height within the test RPC. Arguments --------- blocks : int Number of new blocks to be mined timestamp : int Timestamp of the final block being mined. If multiple blocks are mined, they will be placed at equal intervals starting at `chain.time()` and ending at `timestamp`. timedelta : int Timedelta for the final block to be mined. If given, the final block will have a timestamp of `chain.time() + timedelta` Returns ------- int Current block height """ if not isinstance(blocks, int): raise TypeError("`blocks` must be an integer value") if timedelta is not None and timestamp is not None: raise ValueError("Cannot use both `timestamp` and `timedelta`") if timedelta is not None: timestamp = self.time() + timedelta if timestamp is None: params: List = [[] for i in range(blocks)] elif blocks == 1: params = [[timestamp]] else: now = self.time() duration = (timestamp - now) / (blocks - 1) params = [[round(now + duration * i)] for i in range(blocks)] for i in range(blocks): rpc.Rpc().mine(*params[i]) if timestamp is not None: self.sleep(0) self._redo_buffer.clear() self._current_id = rpc.Rpc().snapshot() return web3.eth.block_number
def sleep(self, seconds: int) -> None: """ Increase the time within the test RPC. Arguments --------- seconds : int Number of seconds to increase the time by """ if not isinstance(seconds, int): raise TypeError("seconds must be an integer value") self._time_offset = int(rpc.Rpc().sleep(seconds)) if seconds: self._redo_buffer.clear() self._current_id = rpc.Rpc().snapshot()
def snapshot(self) -> None: """ Take a snapshot of the current state of the EVM. This action clears the undo buffer. """ self._undo_buffer.clear() self._redo_buffer.clear() self._snapshot_id = self._current_id = rpc.Rpc().snapshot()
def _add_to_undo_buffer(self, tx: Any, fn: Any, args: Tuple, kwargs: Dict) -> None: with self._undo_lock: tx._confirmed.wait() self._undo_buffer.append((self._current_id, fn, args, kwargs)) if self._redo_buffer and (fn, args, kwargs) == self._redo_buffer[-1]: self._redo_buffer.pop() else: self._redo_buffer.clear() self._current_id = rpc.Rpc().snapshot()
def _add_to_undo_buffer(self, tx: Any, fn: Any, args: Tuple, kwargs: Dict) -> None: with self._undo_lock: tx._confirmed.wait() self._undo_buffer.append((self._current_id, fn, args, kwargs)) if self._redo_buffer and (fn, args, kwargs) == self._redo_buffer[-1]: self._redo_buffer.pop() else: self._redo_buffer.clear() self._current_id = rpc.Rpc().snapshot() # ensure the local time offset is correct, in case it was modified by the transaction self.sleep(0)
def _revert(self, id_: int) -> int: rpc_client = rpc.Rpc() if web3.isConnected() and not web3.eth.block_number and not self._time_offset: _notify_registry(0) return rpc_client.snapshot() rpc_client.revert(id_) id_ = rpc_client.snapshot() try: self.sleep(0) except NotImplementedError: pass _notify_registry() return id_
def reset(self) -> int: """ Revert the EVM to the initial state when loaded. This action clears the undo buffer. Returns ------- int Current block height """ self._snapshot_id = None self._undo_buffer.clear() self._redo_buffer.clear() if self._reset_id is None: self._reset_id = self._current_id = rpc.Rpc().snapshot() _notify_registry(0) else: self._reset_id = self._current_id = self._revert(self._reset_id) return web3.eth.block_number