defmodule Etherex.Time do
@moduledoc """
Some Ethereum clients support jumping through time simulating time
events like advance the time and the blocks or set and revert to a
snapshot.
Ganache-cli, for example, support the following non-standard JSON
RPC methods:
- evm_snapshot : Snapshot the state of the blockchain at the current
block. Takes no parameters. Returns the integer id of the snapshot
created. A snapshot can only be used (reverted) once.
- evm_revert : Revert the state of the blockchain to a previous
snapshot. Takes a single parameter, which is the snapshot id to
revert to. This deletes the given snapshot, as well as any
snapshots taken after.
- evm_increaseTime : Jump forward in time. Takes one parameter,
which is the amount of time to increase in seconds. Returns the
total time adjustment, in seconds.
- evm_mine : Force a block to be mined. Takes one optional
parameter, which is the timestamp a block should setup as the
mining time. Mines a block independent of whether or not mining is
started or stopped.
"""
require Logger
alias Ethereumex.HttpClient, as: JsonRPC
alias Etherex
import Etherex.Helpers, only: [decode_json_rpc_error: 1, encode_quantity: 1, decode_quantity: 1]
@doc """
Forces a block to be mined. Takes one optional parameter, which is
the timestamp a block should setup as the mining time. Returns the
block mined.
"""
@spec mine(integer() | nil) :: {:ok, Etherex.quantity()} | {:error, Etherex.error()}
def mine(time \\ nil) do
params = if is_nil(time), do: [], else: [encode_quantity(time)]
case JsonRPC.request("evm_mine", params, []) do
{:ok, _} ->
block_number = Etherex.block_number!()
Logger.info("Block #{block_number} mined")
{:ok, block_number}
error ->
decode_json_rpc_error(error)
end
end
@doc """
Enables automatic mining.
"""
@spec miner_start() :: :ok | {:error, Etherex.error()}
def miner_start() do
case JsonRPC.request("miner_start", [], []) do
{:ok, _} -> :ok
error -> decode_json_rpc_error(error)
end
end
@doc """
Disables automatic mining.
"""
@spec miner_stop() :: :ok | {:error, Etherex.error()}
def miner_stop() do
case JsonRPC.request("miner_stop", [], []) do
{:ok, _} -> :ok
error -> decode_json_rpc_error(error)
end
end
@spec snapshot() :: {:ok, non_neg_integer()} | {:error, Etherex.error()}
def snapshot() do
case JsonRPC.request("evm_snapshot", [], []) do
{:ok, id} -> {:ok, decode_quantity(id)}
error -> decode_json_rpc_error(error)
end
end
@spec revert(id :: non_neg_integer()) :: :ok | {:error, Etherex.error()}
def revert(id) do
case JsonRPC.request("evm_revert", [encode_quantity(id)], []) do
{:ok, _} -> :ok
error -> decode_json_rpc_error(error)
end
end
end