Commit 2f720609 authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into fix-bootnode-flag

parents b8a4b1ec c4d25ebc
---
'@eth-optimism/core-utils': patch
---
Delete legacy core-utils
---
'@eth-optimism/fault-detector': major
'@eth-optimism/sdk': major
---
Make optimism/sdk default to bedrock mode
---
'@eth-optimism/fault-detector': patch
---
Fix false error to warning
---
'@eth-optimism/chain-mon': minor
'@eth-optimism/core-utils': patch
---
Added a new service wallet-mon to identify unexpected transfers from key accounts
---
'@eth-optimism/fault-detector': patch
---
Add better source maps and developer support
---
'@eth-optimism/chain-mon': patch
---
Fixed an issue with logging the wrong timestamp.
---
'@eth-optimism/contracts-bedrock': minor
---
Fix issue with deposits running out of gas
...@@ -59,6 +59,38 @@ commands: ...@@ -59,6 +59,38 @@ commands:
pip3 install -r requirements.txt pip3 install -r requirements.txt
python3 main.py "<<parameters.patterns>>" python3 main.py "<<parameters.patterns>>"
jobs: jobs:
cannon-go-lint-and-test:
docker:
- image: us-docker.pkg.dev/oplabs-tools-artifacts/images/ci-builder:latest
resource_class: medium
steps:
- checkout
- check-changed:
patterns: cannon,packages/contracts-bedrock/contracts/cannon
- run:
name: prep Cannon results dir
command: mkdir -p /tmp/test-results
- run:
name: build Cannon example binaries
command: make elf # only compile ELF binaries with Go, we do not have MIPS GCC for creating the debug-dumps.
working_directory: cannon/example
- run:
name: Cannon Go lint
command: |
golangci-lint run -E goimports,sqlclosecheck,bodyclose,asciicheck,misspell,errorlint --timeout 5m -e "errors.As" -e "errors.Is" ./...
working_directory: cannon
- run:
name: Cannon Go tests
command: |
gotestsum --format=standard-verbose --junitfile=/tmp/test-results/cannon.xml \
-- -parallel=2 -coverpkg=github.com/ethereum-optimism/optimism/cannon/... -coverprofile=coverage.out ./...
working_directory: cannon
- run:
name: upload Cannon coverage
command: codecov --verbose --clean --flags cannon-go-tests
- store_test_results:
path: /tmp/test-results
yarn-monorepo: yarn-monorepo:
docker: docker:
- image: us-docker.pkg.dev/oplabs-tools-artifacts/images/ci-builder:latest - image: us-docker.pkg.dev/oplabs-tools-artifacts/images/ci-builder:latest
...@@ -1387,13 +1419,14 @@ workflows: ...@@ -1387,13 +1419,14 @@ workflows:
- op-challenger-docker-build - op-challenger-docker-build
- check-generated-mocks-op-node - check-generated-mocks-op-node
- check-generated-mocks-op-service - check-generated-mocks-op-service
- cannon-go-lint-and-test
release: release:
jobs: jobs:
- hold: - hold:
type: approval type: approval
filters: filters:
tags: tags:
only: /^(fault-detector|proxyd|indexer|op-[a-z0-9\-]*)\/v.*/ only: /^(fault-detector|proxyd|indexer|ci-builder|op-[a-z0-9\-]*)\/v.*/
branches: branches:
ignore: /.*/ ignore: /.*/
- docker-release: - docker-release:
...@@ -1522,10 +1555,8 @@ workflows: ...@@ -1522,10 +1555,8 @@ workflows:
- oplabs-gcr-release - oplabs-gcr-release
requires: requires:
- hold - hold
release-ci-builder: - docker-release:
jobs: name: ci-builder-docker-release
- docker-publish:
name: ci-builder-docker-publish
filters: filters:
tags: tags:
only: /^ci-builder\/v.*/ only: /^ci-builder\/v.*/
...@@ -1537,6 +1568,8 @@ workflows: ...@@ -1537,6 +1568,8 @@ workflows:
docker_context: ./ops/docker/ci-builder docker_context: ./ops/docker/ci-builder
context: context:
- oplabs-gcr - oplabs-gcr
requires:
- hold
scheduled-fpp: scheduled-fpp:
triggers: triggers:
- schedule: - schedule:
......
node_modules
artifacts
cache
.*.swp
venv
.idea
*.log
example/bin
contracts/out
state.json
*.json
*.pprof
*.out
MIT License
Copyright (c) 2021 Optimism
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
<!--![cannon](https://upload.wikimedia.org/wikipedia/commons/8/80/Cannon%2C_Château_du_Haut-Koenigsbourg%2C_France.jpg)-->
<!--![cannon](https://cdn1.epicgames.com/ue/product/Featured/SCIFIWEAPONBUNDLE_featured-894x488-83fbc936b6d86edcbbe892b1a6780224.png)-->
<!--![cannon](https://static.wikia.nocookie.net/ageofempires/images/8/80/Bombard_cannon_aoe2DE.png/revision/latest/top-crop/width/360/height/360?cb=20200331021834)-->
<!--![cannon](https://paradacreativa.es/wp-content/uploads/2021/05/Canon-orbital-GTA-01.jpg)-->
---
Cannon *(cannon cannon cannon)* is an onchain MIPS instruction emulator.
Cannon supports EVM-equivalent fault proofs by enabling Geth to run onchain,
one instruction at a time, as part of an interactive dispute game.
* It's Go code
* ...that runs an EVM
* ...emulating a MIPS machine
* ...running compiled Go code
* ...that runs an EVM
For more information, see [Docs](./docs/README.md).
## Usage
```shell
# Build op-program server-mode and MIPS-client binaries.
cd ../op-program
make op-program # build
# Switch back to cannon, and build the CLI
cd ../cannon
go build -o cannon .
# Transform MIPS op-program client binary into first VM state.
# This outputs state.json (VM state) and meta.json (for debug symbols).
./cannon load-elf --path=../op-program/bin/op-program-client.elf
# Run cannon emulator (with example inputs)
# Note that the server-mode op-program command is passed into cannon (after the --),
# it runs as sub-process to provide the pre-image data.
#
# Note:
# - The L2 RPC is an archive L2 node on OP goerli.
# - The L1 RPC is a non-archive RPC, also change `--l1.rpckind` to reflect the correct L1 RPC type.
./cannon run
--pprof.cpu
--info-at '%10000000'
--proof-at never
--input ./state.json
--
../op-program/bin/op-program
--l2 http://127.0.0.1:8745
--l1 http://127.0.0.1:8645
--l1.trustrpc
--l1.rpckind debug_geth
--log.format terminal
--l2.head 0xedc79de4d616a9100fdd42192224580daee81ea3d6303de8089d48a6c1bf4816
--network goerli
--l1.head 0x204f815790ca3bb43526ad60ebcc64784ec809bdc3550e82b54a0172f981efab
--l2.claim 0x530658ab1b1b3ff4829731fc8d5955f0e6b8410db2cd65b572067ba58df1f2b9
--l2.blocknumber 8813570
--datadir /tmp/fpp-database
--server
# Add --proof-at '=12345' (or pick other pattern, see --help)
# to pick a step to build a proof for (e.g. exact step, every N steps, etc.)
# Also see `./cannon run --help` for more options
```
## Contracts
The Cannon contracts:
- `MIPS.sol`: A MIPS emulator implementation, to run a single instruction onchain, with merkleized VM memory.
- `PreimageOracle.sol`: implements the pre-image oracle ABI, to support the instruction execution pre-image requests.
The smart-contracts are integrated into the Optimism monorepo contracts:
[`../packages/contracts-bedrock/contracts/cannon`](../packages/contracts-bedrock/contracts/cannon)
## `mipsevm`
`mipsevm` is Go tooling to test the onchain MIPS implementation, and generate proof data.
## `example`
Example programs that can be run and proven with Cannon.
Optional dependency, but required for `mipsevm` Go tests.
See [`example/Makefile`](./example/Makefile) for building the example MIPS binaries.
## License
MIT, see [`LICENSE`](./LICENSE) file.
**Note: This code is unaudited.**
In NO WAY should it be used to secure any monetary value before testing and auditing.
This is experimental software, and should be treated as such.
The authors of this project make no guarantees of security of ANY KIND.
package cmd
import (
"encoding/json"
"errors"
"fmt"
"io"
"os"
)
func loadJSON[X any](inputPath string) (*X, error) {
if inputPath == "" {
return nil, errors.New("no path specified")
}
f, err := os.OpenFile(inputPath, os.O_RDONLY, 0)
if err != nil {
return nil, fmt.Errorf("failed to open file %q: %w", inputPath, err)
}
defer f.Close()
var state X
if err := json.NewDecoder(f).Decode(&state); err != nil {
return nil, fmt.Errorf("failed to decode file %q: %w", inputPath, err)
}
return &state, nil
}
func writeJSON[X any](outputPath string, value X, outIfEmpty bool) error {
var out io.Writer
if outputPath != "" {
f, err := os.OpenFile(outputPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
if err != nil {
return fmt.Errorf("failed to open output file: %w", err)
}
defer f.Close()
out = f
} else if outIfEmpty {
out = os.Stdout
} else {
return nil
}
enc := json.NewEncoder(out)
if err := enc.Encode(value); err != nil {
return fmt.Errorf("failed to encode to JSON: %w", err)
}
_, err := out.Write([]byte{'\n'})
if err != nil {
return fmt.Errorf("failed to append new-line: %w", err)
}
return nil
}
package cmd
import (
"debug/elf"
"fmt"
"github.com/urfave/cli/v2"
"github.com/ethereum-optimism/optimism/cannon/mipsevm"
)
var (
LoadELFPathFlag = &cli.PathFlag{
Name: "path",
Usage: "Path to 32-bit big-endian MIPS ELF file",
TakesFile: true,
Required: true,
}
LoadELFPatchFlag = &cli.StringSliceFlag{
Name: "patch",
Usage: "Type of patching to do",
Value: cli.NewStringSlice("go", "stack"),
Required: false,
}
LoadELFOutFlag = &cli.PathFlag{
Name: "out",
Usage: "Output path to write JSON state to. State is dumped to stdout if set to empty string.",
Value: "state.json",
Required: false,
}
LoadELFMetaFlag = &cli.PathFlag{
Name: "meta",
Usage: "Write metadata file, for symbol lookup during program execution. None if empty.",
Value: "meta.json",
Required: false,
}
)
func LoadELF(ctx *cli.Context) error {
elfPath := ctx.Path(LoadELFPathFlag.Name)
elfProgram, err := elf.Open(elfPath)
if err != nil {
return fmt.Errorf("failed to open ELF file %q: %w", elfPath, err)
}
if elfProgram.Machine != elf.EM_MIPS {
return fmt.Errorf("ELF is not big-endian MIPS R3000, but got %q", elfProgram.Machine.String())
}
state, err := mipsevm.LoadELF(elfProgram)
if err != nil {
return fmt.Errorf("failed to load ELF data into VM state: %w", err)
}
for _, typ := range ctx.StringSlice(LoadELFPatchFlag.Name) {
switch typ {
case "stack":
err = mipsevm.PatchStack(state)
case "go":
err = mipsevm.PatchGo(elfProgram, state)
default:
return fmt.Errorf("unrecognized form of patching: %q", typ)
}
if err != nil {
return fmt.Errorf("failed to apply patch %s: %w", typ, err)
}
}
meta, err := mipsevm.MakeMetadata(elfProgram)
if err != nil {
return fmt.Errorf("failed to compute program metadata: %w", err)
}
if err := writeJSON[*mipsevm.Metadata](ctx.Path(LoadELFMetaFlag.Name), meta, false); err != nil {
return fmt.Errorf("failed to output metadata: %w", err)
}
return writeJSON[*mipsevm.State](ctx.Path(LoadELFOutFlag.Name), state, true)
}
var LoadELFCommand = &cli.Command{
Name: "load-elf",
Usage: "Load ELF file into Cannon JSON state",
Description: "Load ELF file into Cannon JSON state, optionally patch out functions",
Action: LoadELF,
Flags: []cli.Flag{
LoadELFPathFlag,
LoadELFPatchFlag,
LoadELFOutFlag,
LoadELFMetaFlag,
},
}
package cmd
import (
"io"
"github.com/ethereum/go-ethereum/log"
)
func Logger(w io.Writer, lvl log.Lvl) log.Logger {
h := log.StreamHandler(w, log.LogfmtFormat())
h = log.SyncHandler(h)
h = log.LvlFilterHandler(lvl, h)
l := log.New()
l.SetHandler(h)
return l
}
package cmd
import (
"fmt"
"strconv"
"strings"
"github.com/ethereum-optimism/optimism/cannon/mipsevm"
)
type StepMatcher func(st *mipsevm.State) bool
type StepMatcherFlag struct {
repr string
matcher StepMatcher
}
func MustStepMatcherFlag(pattern string) *StepMatcherFlag {
out := new(StepMatcherFlag)
if err := out.Set(pattern); err != nil {
panic(err)
}
return out
}
func (m *StepMatcherFlag) Set(value string) error {
m.repr = value
if value == "" || value == "never" {
m.matcher = func(st *mipsevm.State) bool {
return false
}
} else if value == "always" {
m.matcher = func(st *mipsevm.State) bool {
return true
}
} else if strings.HasPrefix(value, "=") {
when, err := strconv.ParseUint(value[1:], 0, 64)
if err != nil {
return fmt.Errorf("failed to parse step number: %w", err)
}
m.matcher = func(st *mipsevm.State) bool {
return st.Step == when
}
} else if strings.HasPrefix(value, "%") {
when, err := strconv.ParseUint(value[1:], 0, 64)
if err != nil {
return fmt.Errorf("failed to parse step interval number: %w", err)
}
m.matcher = func(st *mipsevm.State) bool {
return st.Step%when == 0
}
} else {
return fmt.Errorf("unrecognized step matcher: %q", value)
}
return nil
}
func (m *StepMatcherFlag) String() string {
return m.repr
}
func (m *StepMatcherFlag) Matcher() StepMatcher {
if m.matcher == nil { // Set(value) is not called for omitted inputs, default to never matching.
return func(st *mipsevm.State) bool {
return false
}
}
return m.matcher
}
package cmd
import (
"fmt"
"os"
"os/exec"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
"github.com/urfave/cli/v2"
"github.com/pkg/profile"
"github.com/ethereum-optimism/optimism/cannon/mipsevm"
preimage "github.com/ethereum-optimism/optimism/op-preimage"
)
var (
RunInputFlag = &cli.PathFlag{
Name: "input",
Usage: "path of input JSON state. Stdin if left empty.",
TakesFile: true,
Value: "state.json",
Required: true,
}
RunOutputFlag = &cli.PathFlag{
Name: "output",
Usage: "path of output JSON state. Stdout if left empty.",
TakesFile: true,
Value: "out.json",
Required: false,
}
patternHelp = "'never' (default), 'always', '=123' at exactly step 123, '%123' for every 123 steps"
RunProofAtFlag = &cli.GenericFlag{
Name: "proof-at",
Usage: "step pattern to output proof at: " + patternHelp,
Value: new(StepMatcherFlag),
Required: false,
}
RunProofFmtFlag = &cli.StringFlag{
Name: "proof-fmt",
Usage: "format for proof data output file names. Proof data is written to stdout if empty.",
Value: "proof-%d.json",
Required: false,
}
RunSnapshotAtFlag = &cli.GenericFlag{
Name: "snapshot-at",
Usage: "step pattern to output snapshots at: " + patternHelp,
Value: new(StepMatcherFlag),
Required: false,
}
RunSnapshotFmtFlag = &cli.StringFlag{
Name: "snapshot-fmt",
Usage: "format for snapshot output file names.",
Value: "state-%d.json",
Required: false,
}
RunStopAtFlag = &cli.GenericFlag{
Name: "stop-at",
Usage: "step pattern to stop at: " + patternHelp,
Value: new(StepMatcherFlag),
Required: false,
}
RunMetaFlag = &cli.PathFlag{
Name: "meta",
Usage: "path to metadata file for symbol lookup for enhanced debugging info durign execution.",
Value: "meta.json",
Required: false,
}
RunInfoAtFlag = &cli.GenericFlag{
Name: "info-at",
Usage: "step pattern to print info at: " + patternHelp,
Value: MustStepMatcherFlag("%100000"),
Required: false,
}
RunPProfCPU = &cli.BoolFlag{
Name: "pprof.cpu",
Usage: "enable pprof cpu profiling",
}
)
type Proof struct {
Step uint64 `json:"step"`
Pre common.Hash `json:"pre"`
Post common.Hash `json:"post"`
StepInput hexutil.Bytes `json:"step-input"`
OracleInput hexutil.Bytes `json:"oracle-input"`
}
type rawHint string
func (rh rawHint) Hint() string {
return string(rh)
}
type rawKey [32]byte
func (rk rawKey) PreimageKey() [32]byte {
return rk
}
type ProcessPreimageOracle struct {
pCl *preimage.OracleClient
hCl *preimage.HintWriter
cmd *exec.Cmd
}
func NewProcessPreimageOracle(name string, args []string) (*ProcessPreimageOracle, error) {
if name == "" {
return &ProcessPreimageOracle{}, nil
}
pClientRW, pOracleRW, err := preimage.CreateBidirectionalChannel()
if err != nil {
return nil, err
}
hClientRW, hOracleRW, err := preimage.CreateBidirectionalChannel()
if err != nil {
return nil, err
}
cmd := exec.Command(name, args...) // nosemgrep
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.ExtraFiles = []*os.File{
hOracleRW.Reader(),
hOracleRW.Writer(),
pOracleRW.Reader(),
pOracleRW.Writer(),
}
out := &ProcessPreimageOracle{
pCl: preimage.NewOracleClient(pClientRW),
hCl: preimage.NewHintWriter(hClientRW),
cmd: cmd,
}
return out, nil
}
func (p *ProcessPreimageOracle) Hint(v []byte) {
if p.hCl == nil { // no hint processor
return
}
p.hCl.Hint(rawHint(v))
}
func (p *ProcessPreimageOracle) GetPreimage(k [32]byte) []byte {
if p.pCl == nil {
panic("no pre-image retriever available")
}
return p.pCl.Get(rawKey(k))
}
func (p *ProcessPreimageOracle) Start() error {
if p.cmd == nil {
return nil
}
return p.cmd.Start()
}
func (p *ProcessPreimageOracle) Close() error {
if p.cmd == nil {
return nil
}
_ = p.cmd.Process.Signal(os.Interrupt)
// Go 1.20 feature, to introduce later
//p.cmd.WaitDelay = time.Second * 10
err := p.cmd.Wait()
if err, ok := err.(*exec.ExitError); ok {
if err.Success() {
return nil
}
}
return err
}
type StepFn func(proof bool) (*mipsevm.StepWitness, error)
func Guard(proc *os.ProcessState, fn StepFn) StepFn {
return func(proof bool) (*mipsevm.StepWitness, error) {
wit, err := fn(proof)
if err != nil {
if proc.Exited() {
return nil, fmt.Errorf("pre-image server exited with code %d, resulting in err %w", proc.ExitCode(), err)
} else {
return nil, err
}
}
return wit, nil
}
}
var _ mipsevm.PreimageOracle = (*ProcessPreimageOracle)(nil)
func Run(ctx *cli.Context) error {
if ctx.Bool(RunPProfCPU.Name) {
defer profile.Start(profile.NoShutdownHook, profile.ProfilePath("."), profile.CPUProfile).Stop()
}
state, err := loadJSON[mipsevm.State](ctx.Path(RunInputFlag.Name))
if err != nil {
return err
}
l := Logger(os.Stderr, log.LvlInfo)
outLog := &mipsevm.LoggingWriter{Name: "program std-out", Log: l}
errLog := &mipsevm.LoggingWriter{Name: "program std-err", Log: l}
// split CLI args after first '--'
args := ctx.Args().Slice()
for i, arg := range args {
if arg == "--" {
args = args[i+1:]
break
}
}
if len(args) == 0 {
args = []string{""}
}
po, err := NewProcessPreimageOracle(args[0], args[1:])
if err != nil {
return fmt.Errorf("failed to create pre-image oracle process: %w", err)
}
if err := po.Start(); err != nil {
return fmt.Errorf("failed to start pre-image oracle server: %w", err)
}
defer func() {
if err := po.Close(); err != nil {
l.Error("failed to close pre-image server", "err", err)
}
}()
stopAt := ctx.Generic(RunStopAtFlag.Name).(*StepMatcherFlag).Matcher()
proofAt := ctx.Generic(RunProofAtFlag.Name).(*StepMatcherFlag).Matcher()
snapshotAt := ctx.Generic(RunSnapshotAtFlag.Name).(*StepMatcherFlag).Matcher()
infoAt := ctx.Generic(RunInfoAtFlag.Name).(*StepMatcherFlag).Matcher()
var meta *mipsevm.Metadata
if metaPath := ctx.Path(RunMetaFlag.Name); metaPath == "" {
l.Info("no metadata file specified, defaulting to empty metadata")
meta = &mipsevm.Metadata{Symbols: nil} // provide empty metadata by default
} else {
if m, err := loadJSON[mipsevm.Metadata](metaPath); err != nil {
return fmt.Errorf("failed to load metadata: %w", err)
} else {
meta = m
}
}
us := mipsevm.NewInstrumentedState(state, po, outLog, errLog)
proofFmt := ctx.String(RunProofFmtFlag.Name)
snapshotFmt := ctx.String(RunSnapshotFmtFlag.Name)
stepFn := us.Step
if po.cmd != nil {
stepFn = Guard(po.cmd.ProcessState, stepFn)
}
start := time.Now()
startStep := state.Step
// avoid symbol lookups every instruction by preparing a matcher func
sleepCheck := meta.SymbolMatcher("runtime.notesleep")
for !state.Exited {
if state.Step%100 == 0 { // don't do the ctx err check (includes lock) too often
if err := ctx.Context.Err(); err != nil {
return err
}
}
step := state.Step
if infoAt(state) {
delta := time.Since(start)
l.Info("processing",
"step", step,
"pc", mipsevm.HexU32(state.PC),
"insn", mipsevm.HexU32(state.Memory.GetMemory(state.PC)),
"ips", float64(step-startStep)/(float64(delta)/float64(time.Second)),
"pages", state.Memory.PageCount(),
"mem", state.Memory.Usage(),
"name", meta.LookupSymbol(state.PC),
)
}
if sleepCheck(state.PC) { // don't loop forever when we get stuck because of an unexpected bad program
return fmt.Errorf("got stuck in Go sleep at step %d", step)
}
if stopAt(state) {
break
}
if snapshotAt(state) {
if err := writeJSON[*mipsevm.State](fmt.Sprintf(snapshotFmt, step), state, false); err != nil {
return fmt.Errorf("failed to write state snapshot: %w", err)
}
}
if proofAt(state) {
preStateHash := crypto.Keccak256Hash(state.EncodeWitness())
witness, err := stepFn(true)
if err != nil {
return fmt.Errorf("failed at proof-gen step %d (PC: %08x): %w", step, state.PC, err)
}
postStateHash := crypto.Keccak256Hash(state.EncodeWitness())
proof := &Proof{
Step: step,
Pre: preStateHash,
Post: postStateHash,
StepInput: witness.EncodeStepInput(),
}
if witness.HasPreimage() {
inp, err := witness.EncodePreimageOracleInput()
if err != nil {
return fmt.Errorf("failed to encode pre-image oracle input: %w", err)
}
proof.OracleInput = inp
}
if err := writeJSON[*Proof](fmt.Sprintf(proofFmt, step), proof, true); err != nil {
return fmt.Errorf("failed to write proof data: %w", err)
}
} else {
_, err = stepFn(false)
if err != nil {
return fmt.Errorf("failed at step %d (PC: %08x): %w", step, state.PC, err)
}
}
}
if err := writeJSON[*mipsevm.State](ctx.Path(RunOutputFlag.Name), state, true); err != nil {
return fmt.Errorf("failed to write state output: %w", err)
}
return nil
}
var RunCommand = &cli.Command{
Name: "run",
Usage: "Run VM step(s) and generate proof data to replicate onchain.",
Description: "Run VM step(s) and generate proof data to replicate onchain. See flags to match when to output a proof, a snapshot, or to stop early.",
Action: Run,
Flags: []cli.Flag{
RunInputFlag,
RunOutputFlag,
RunProofAtFlag,
RunProofFmtFlag,
RunSnapshotAtFlag,
RunSnapshotFmtFlag,
RunStopAtFlag,
RunMetaFlag,
RunInfoAtFlag,
RunPProfCPU,
},
}
# Cannon Overview
Cannon has two main components:
- Onchain `MIPS.sol`: EVM implementation to verify execution of a single MIPS instruction.
- Offchain `mipsevm`: Go implementation to produce a proof for any MIPS instruction to verify onchain.
Between these two modes of operation, the [witness data](#witness-data) is essential,
to reproduce the same instruction onchain as offchain.
## Onchain `MIPS.sol`
This is an onchain implementation of big-endian 32-bit MIPS instruction execution.
This covers MIPS III, R3000, as required by the `mips` Go compiler/runtime target.
The systemcall instruction is implemented to simulate a minimal subset of the Linux kernel,
just enough to serve the needs of a basic Go program:
allocate memory, read/write to certain file-descriptors, and exit.
Note that this does not include concurrency related system calls: when running Go programs,
the GC has to be disabled, since it runs concurrently.
This is done by patching out specific runtime functions that start the GC,
by simply inserting jumps to the return-address, before the functions spin up any additional threads.
## Offchain `mipsevm`
This is an instrumented emulator, also running big-endian 32-bit MIPS, that executes one step at a time,
and maintains the same state as used for onchain execution.
The difference is that it has access to the full memory, and pre-image oracle.
And as it executes each step, it can optionally produce the witness data for the step, to repeat it onchain.
The Cannon CLI is used to load a program into an initial state,
transition it N steps quickly without witness generation, and 1 step while producing a witness.
`mipsevm` is backed by the Unicorn emulator, but instrumented for proof generation,
and handles delay-slots by isolating each individual instruction and tracking `nextPC`
to emulate the delayed `PC` changes after delay-slot execution.
## Witness Data
There are 3 types of witness data involved in onchain execution:
- [Packed State](#packed-state)
- [Memory proofs](#memory-proofs)
- [Pre-image data](#pre-image-data)
### Packed State
The following state is packed together, and provided in every executed onchain instruction:
```solidity
struct State {
bytes32 memRoot;
bytes32 preimageKey;
uint32 preimageOffset;
uint32 pc;
uint32 nextPC;
uint32 lo;
uint32 hi;
uint32 heap;
uint8 exitCode;
bool exited;
uint64 step;
uint32[32] registers;
}
```
The packed state is small! The `State` data can be packed in such a small amount of EVM words,
that it is more efficient to fully provide it, than to create a proof for each individual part involved in execution.
The memory is represented as a merkle-tree root, committing to a binary merkle tree of all memory data,
see [memory proofs](#memory-proofs).
The `State` covers all general purpose registers, as well as the `lo`, `hi` and `pc` values.
`nextPC` helps pre-schedule the program counter change, to emulate delay-slot behavior of MIPS
after branch and jump instructions.
The program stops changing the state when `exited` is set to true. The exit-code is remembered,
to determine if the program is successful, or panicked/exited in some unexpected way.
This outcome can be used to determine truthiness of claims that are verified as part of the program execution.
The `heap` value is a special value, used to emulate a growing heap, to map new memory upon `mmap` calls by the program.
No memory reads/writes are actually illegal however, mmap-ing is purely to satisfy program runtimes that
need the memory-pointer result of the syscall to locate free memory.
The `preimageKey` and `preimageOffset` are backing the in-flight communication of [pre-image data](#pre-image-data).
The VM `stateHash` is computed as `keccak256(encoded_packed_state)`,
where `encoded_packed_state` is the concatenation of all state-values (all `uint` values are big-endian).
### Memory proofs
Simplicity is key here. Previous versions of Cannon used to overlap memory and register state,
and represent it with a Merkle Patricia Trie.
This added a lot of complexity, as there would be multiple dynamically-sized MPT proofs,
with read and write operations, during a single instruction.
Instead, memory in Cannon is now represented as a binary merkle tree:
The tree has a fixed-depth of 27 levels, with leaf values of 32 bytes each.
This spans the full 32-bit address space: `2**27 * 32 = 2**32`.
Each leaf contains the memory at that part of the tree.
The tree is efficiently allocated, since the root of fully zeroed sub-trees
can be computed without actually creating the full-subtree: `zero_hash[d] = hash(zero_hash[d-1], zero_hash[d-1])`,
until the base-case of `zero_hash[0] == bytes32(0)`.
Nodes in this memory tree are combined as: `out = keccak256(left ++ right)`, where `++` is concatenation,
and `left` and `right` are the 32-byte outputs of the respective sub-trees or the leaf values themselves.
Individual leaf nodes are not hashed.
The proof format is a concatenated byte array of 28 `bytes32`. The first `bytes32` is the leaf value,
and the remaining 27 `bytes32` are the sibling nodes up till the root of the tree,
along the branch of the leaf value, starting from the bottom.
To verify the proof, start with the leaf value as `node`, and combine it with respective sibling values:
`node = keccak256(node ++ sibling)` or `node = keccak256(sibling ++ node)`,
depending the position of `node` at that level of the tree.
During the onchain execution, each instruction only executes 1 or 2 memory reads, followed by 0 or 1 writes,
where the write is over the same memory as was last read.
The memory access is specifically:
- instruction (4 byte) read at `PC`
- load or syscall mem read, always aligned 4 bytes, read at any `addr`
- store or syscall mem write, always aligned 4 bytes, at ths same `addr`
Writing only once, at the last read leaf, also means that the leaf can be safely updated and the same proof-data
that was used to verify the read, can be used to reconstruct the new `memRoot` of the memory tree,
since all sibling data that is combined with the new leaf value was already authenticated during the read part.
### Pre-image data
Pre-image data is accessed through syscalls exclusively.
The OP-stack fault-proof [Pre-image Oracle specs](../../specs/fault-proof.md#pre-image-oracle)
define the ABI for communicating pre-images.
This ABI is implemented by the VM by intercepting the `read`/`write` syscalls to specific file descriptors:
- `hint client read = 3`: used by the client to send hint data to the host. Optional, implemented as blocking.
- `hint client write = 4`: used by the client to wait for the host. Always instant, since the above is implemented as blocking.
- `preimage client read = 5`: used by the client to read pre-image data, starting from the latest pre-image reading offset.
- `preimage client write = 6`: used by the client to change the pre-image key. The key may change a little bit at a time. The last 32 written bytes count as key for retrieval when reading the pre-image. Changing the key also resets the read offset to 0.
The data is loaded into `PreimageOracle.sol` using the respective loading function based on the pre-image type.
And then retrieved during execution of the `read` syscall.
Note that although the oracle provides up to 32 bytes of the pre-image,
Cannon only supports reading at most 4 bytes at a time, to unify the memory operations with regular load/stores.
## Usage in Dispute Game
The onchain MIPS execution functions as base-case of an interactive dispute game.
The dispute game narrows down a sequence of disputed instructions to a single disputed instruction.
This instruction can then be executed onchain to determine objective truth.
The Dispute Game itself is out of scope for Cannon: Cannon is just one example of a fault-proof VM that
can be used to resolve disputes.
all: elf dump
.PHONY: elf
elf: $(patsubst %/go.mod,bin/%.elf,$(wildcard */go.mod))
.PHONY: dump
dump: $(patsubst %/go.mod,bin/%.dump,$(wildcard */go.mod))
bin:
mkdir bin
# take any directory with a go mod, and build an ELF
# verify output with: readelf -h bin/<name>.elf
# result is mips32, big endian, R3000
bin/%.elf: bin
cd $(@:bin/%.elf=%) && GOOS=linux GOARCH=mips GOMIPS=softfloat go build -o ../$@ .
# take any ELF and dump it
# TODO: currently have the little-endian toolchain, but should use the big-endian one. The -EB compat flag works though.
bin/%.dump: bin/%.elf
mipsel-linux-gnu-objdump -D --disassembler-options=no-aliases --wide --source -m mips:3000 -EB $(@:%.dump=%.elf) > $@
module claim
go 1.20
require github.com/ethereum-optimism/optimism v0.0.0
require (
golang.org/x/crypto v0.8.0 // indirect
golang.org/x/sys v0.7.0 // indirect
)
replace github.com/ethereum-optimism/optimism v0.0.0 => ../../..
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
package main
import (
"encoding/binary"
"fmt"
"os"
"github.com/ethereum-optimism/optimism/op-preimage"
)
type rawHint string
func (rh rawHint) Hint() string {
return string(rh)
}
func main() {
_, _ = os.Stderr.Write([]byte("started!"))
po := preimage.NewOracleClient(preimage.ClientPreimageChannel())
hinter := preimage.NewHintWriter(preimage.ClientHinterChannel())
preHash := *(*[32]byte)(po.Get(preimage.LocalIndexKey(0)))
diffHash := *(*[32]byte)(po.Get(preimage.LocalIndexKey(1)))
claimData := *(*[8]byte)(po.Get(preimage.LocalIndexKey(2)))
// Hints are used to indicate which things the program will access,
// so the server can be prepared to serve the corresponding pre-images.
hinter.Hint(rawHint(fmt.Sprintf("fetch-state %x", preHash)))
pre := po.Get(preimage.Keccak256Key(preHash))
// Multiple pre-images may be fetched based on a hint.
// E.g. when we need all values of a merkle-tree.
hinter.Hint(rawHint(fmt.Sprintf("fetch-diff %x", diffHash)))
diff := po.Get(preimage.Keccak256Key(diffHash))
diffPartA := po.Get(preimage.Keccak256Key(*(*[32]byte)(diff[:32])))
diffPartB := po.Get(preimage.Keccak256Key(*(*[32]byte)(diff[32:])))
// Example state-transition function: s' = s*a + b
s := binary.BigEndian.Uint64(pre)
a := binary.BigEndian.Uint64(diffPartA)
b := binary.BigEndian.Uint64(diffPartB)
fmt.Printf("computing %d * %d + %d\n", s, a, b)
sOut := s*a + b
sClaim := binary.BigEndian.Uint64(claimData[:])
if sOut != sClaim {
fmt.Printf("claim %d is bad! Correct result is %d\n", sOut, sClaim)
os.Exit(1)
} else {
fmt.Printf("claim %d is good!\n", sOut)
os.Exit(0)
}
}
package main
import "os"
func main() {
_, _ = os.Stdout.Write([]byte("hello world!\n"))
}
package main
import (
"context"
"errors"
"fmt"
"os"
"os/signal"
"syscall"
"github.com/urfave/cli/v2"
"github.com/ethereum-optimism/optimism/cannon/cmd"
)
func main() {
app := cli.NewApp()
app.Name = "cannon"
app.Usage = "MIPS Fault Proof tool"
app.Description = "MIPS Fault Proof tool"
app.Commands = []*cli.Command{
cmd.LoadELFCommand,
cmd.RunCommand,
}
ctx, cancel := context.WithCancel(context.Background())
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
go func() {
for {
<-c
cancel()
fmt.Println("\r\nExiting...")
}
}()
err := app.RunContext(ctx, os.Args)
if err != nil {
if errors.Is(err, ctx.Err()) {
_, _ = fmt.Fprintf(os.Stderr, "command interrupted")
os.Exit(130)
} else {
_, _ = fmt.Fprintf(os.Stderr, "error: %v", err)
os.Exit(1)
}
}
}
mipsevm
mipsevm.test
*.prof
# `mipsevm`
Supported 55 instructions:
```
'addi', 'addiu', 'addu', 'and', 'andi',
'b', 'beq', 'beqz', 'bgez', 'bgtz', 'blez', 'bltz', 'bne', 'bnez',
'clz', 'divu',
'j', 'jal', 'jalr', 'jr',
'lb', 'lbu', 'lui', 'lw', 'lwr',
'mfhi', 'mflo', 'move', 'movn', 'movz', 'mtlo', 'mul', 'multu',
'negu', 'nop', 'not', 'or', 'ori',
'sb', 'sll', 'sllv', 'slt', 'slti', 'sltiu', 'sltu', 'sra', 'srl', 'srlv', 'subu', 'sw', 'swr', 'sync', 'syscall',
'xor', 'xori'
```
To run:
1. Load a program into a state, e.g. using `LoadELF`.
2. Patch the program if necessary: e.g. using `PatchGo` for Go programs, `PatchStack` for empty initial stack, etc.
4. Implement the `PreimageOracle` interface
5. Instrument the emulator with the state, and pre-image oracle, using `NewInstrumentedState`
6. Step through the instrumented state with `Step(proof)`,
where `proof==true` if witness data should be generated. Steps are faster with `proof==false`.
7. Optionally repeat the step on-chain by calling `MIPS.sol` and `PreimageOracle.sol`, using the above witness data.
package mipsevm
import (
"encoding/binary"
"encoding/json"
"fmt"
"math/big"
"os"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-chain-ops/srcmap"
)
var (
StepBytes4 = crypto.Keccak256([]byte("Step(bytes,bytes)"))[:4]
CheatBytes4 = crypto.Keccak256([]byte("cheat(uint256,bytes32,bytes32,uint256)"))[:4]
LoadKeccak256PreimagePartBytes4 = crypto.Keccak256([]byte("loadKeccak256PreimagePart(uint256,bytes)"))[:4]
)
// LoadContracts loads the Cannon contracts, from op-bindings package
func LoadContracts() (*Contracts, error) {
var mips, oracle Contract
mips.DeployedBytecode.Object = hexutil.MustDecode(bindings.MIPSDeployedBin)
mips.DeployedBytecode.SourceMap = bindings.MIPSDeployedSourceMap
oracle.DeployedBytecode.Object = hexutil.MustDecode(bindings.PreimageOracleDeployedBin)
oracle.DeployedBytecode.SourceMap = bindings.PreimageOracleDeployedSourceMap
return &Contracts{
MIPS: &mips,
Oracle: &oracle,
}, nil
}
// LoadContractsFromFiles loads the Cannon contracts, from local filesystem
func LoadContractsFromFiles() (*Contracts, error) {
mips, err := LoadContract("MIPS")
if err != nil {
return nil, err
}
oracle, err := LoadContract("Oracle")
if err != nil {
return nil, err
}
return &Contracts{
MIPS: mips,
Oracle: oracle,
}, nil
}
func LoadContract(name string) (*Contract, error) {
dat, err := os.ReadFile(fmt.Sprintf("../../packages/contracts-bedrock/forge-artifacts/%s.sol/%s.json", name, name))
if err != nil {
return nil, fmt.Errorf("failed to read contract JSON definition of %q: %w", name, err)
}
var out Contract
if err := json.Unmarshal(dat, &out); err != nil {
return nil, fmt.Errorf("failed to parse contract JSON definition of %q: %w", name, err)
}
return &out, nil
}
type Contract struct {
DeployedBytecode struct {
Object hexutil.Bytes `json:"object"`
SourceMap string `json:"sourceMap"`
} `json:"deployedBytecode"`
// ignore abi,bytecode,etc.
}
func (c *Contract) SourceMap(sourcePaths []string) (*srcmap.SourceMap, error) {
return srcmap.ParseSourceMap(sourcePaths, c.DeployedBytecode.Object, c.DeployedBytecode.SourceMap)
}
type Contracts struct {
MIPS *Contract
Oracle *Contract
}
type Addresses struct {
MIPS common.Address
Oracle common.Address
Sender common.Address
FeeRecipient common.Address
}
func NewEVMEnv(contracts *Contracts, addrs *Addresses) (*vm.EVM, *state.StateDB) {
chainCfg := params.MainnetChainConfig
offsetBlocks := uint64(1000) // blocks after shanghai fork
bc := &testChain{startTime: *chainCfg.ShanghaiTime + offsetBlocks*12}
header := bc.GetHeader(common.Hash{}, 17034870+offsetBlocks)
db := rawdb.NewMemoryDatabase()
statedb := state.NewDatabase(db)
state, err := state.New(types.EmptyRootHash, statedb, nil)
if err != nil {
panic(fmt.Errorf("failed to create memory state db: %w", err))
}
blockContext := core.NewEVMBlockContext(header, bc, nil, chainCfg, state)
vmCfg := vm.Config{}
env := vm.NewEVM(blockContext, vm.TxContext{}, state, chainCfg, vmCfg)
// pre-deploy the contracts
env.StateDB.SetCode(addrs.MIPS, contracts.MIPS.DeployedBytecode.Object)
env.StateDB.SetCode(addrs.Oracle, contracts.Oracle.DeployedBytecode.Object)
env.StateDB.SetState(addrs.MIPS, common.Hash{}, addrs.Oracle.Hash())
rules := env.ChainConfig().Rules(header.Number, true, header.Time)
env.StateDB.Prepare(rules, addrs.Sender, addrs.FeeRecipient, &addrs.MIPS, vm.ActivePrecompiles(rules), nil)
return env, state
}
type testChain struct {
startTime uint64
}
func (d *testChain) Engine() consensus.Engine {
return ethash.NewFullFaker()
}
func (d *testChain) GetHeader(h common.Hash, n uint64) *types.Header {
parentHash := common.Hash{0: 0xff}
binary.BigEndian.PutUint64(parentHash[1:], n-1)
return &types.Header{
ParentHash: parentHash,
UncleHash: types.EmptyUncleHash,
Coinbase: common.Address{},
Root: common.Hash{},
TxHash: types.EmptyTxsHash,
ReceiptHash: types.EmptyReceiptsHash,
Bloom: types.Bloom{},
Difficulty: big.NewInt(0),
Number: new(big.Int).SetUint64(n),
GasLimit: 30_000_000,
GasUsed: 0,
Time: d.startTime + n*12,
Extra: nil,
MixDigest: common.Hash{},
Nonce: types.BlockNonce{},
BaseFee: big.NewInt(7),
WithdrawalsHash: &types.EmptyWithdrawalsHash,
}
}
package mipsevm
import (
"bytes"
"debug/elf"
"io"
"math/big"
"os"
"path"
"testing"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/tracers/logger"
"github.com/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/op-chain-ops/srcmap"
)
func testContractsSetup(t *testing.T) (*Contracts, *Addresses) {
contracts, err := LoadContracts()
require.NoError(t, err)
addrs := &Addresses{
MIPS: common.Address{0: 0xff, 19: 1},
Oracle: common.Address{0: 0xff, 19: 2},
Sender: common.Address{0x13, 0x37},
FeeRecipient: common.Address{0xaa},
}
return contracts, addrs
}
func SourceMapTracer(t *testing.T, contracts *Contracts, addrs *Addresses) vm.EVMLogger {
mipsSrcMap, err := contracts.MIPS.SourceMap([]string{"../../packages/contracts-bedrock/contracts/cannon/MIPS.sol"})
require.NoError(t, err)
oracleSrcMap, err := contracts.Oracle.SourceMap([]string{"../../packages/contracts-bedrock/contracts/cannon/PreimageOracle.sol"})
require.NoError(t, err)
return srcmap.NewSourceMapTracer(map[common.Address]*srcmap.SourceMap{addrs.MIPS: mipsSrcMap, addrs.Oracle: oracleSrcMap}, os.Stdout)
}
func MarkdownTracer() vm.EVMLogger {
return logger.NewMarkdownLogger(&logger.Config{}, os.Stdout)
}
func TestEVM(t *testing.T) {
testFiles, err := os.ReadDir("open_mips_tests/test/bin")
require.NoError(t, err)
contracts, addrs := testContractsSetup(t)
var tracer vm.EVMLogger // no-tracer by default, but see SourceMapTracer and MarkdownTracer
//tracer = SourceMapTracer(t, contracts, addrs)
sender := common.Address{0x13, 0x37}
for _, f := range testFiles {
t.Run(f.Name(), func(t *testing.T) {
if f.Name() == "oracle.bin" {
t.Skip("oracle test needs to be updated to use syscall pre-image oracle")
}
env, evmState := NewEVMEnv(contracts, addrs)
env.Config.Tracer = tracer
fn := path.Join("open_mips_tests/test/bin", f.Name())
programMem, err := os.ReadFile(fn)
require.NoError(t, err)
state := &State{PC: 0, NextPC: 4, Memory: NewMemory()}
err = state.Memory.SetMemoryRange(0, bytes.NewReader(programMem))
require.NoError(t, err, "load program into state")
// set the return address ($ra) to jump into when test completes
state.Registers[31] = endAddr
us := NewInstrumentedState(state, nil, os.Stdout, os.Stderr)
for i := 0; i < 1000; i++ {
if us.state.PC == endAddr {
break
}
insn := state.Memory.GetMemory(state.PC)
t.Logf("step: %4d pc: 0x%08x insn: 0x%08x", state.Step, state.PC, insn)
stepWitness, err := us.Step(true)
require.NoError(t, err)
input := stepWitness.EncodeStepInput()
startingGas := uint64(30_000_000)
// we take a snapshot so we can clean up the state, and isolate the logs of this instruction run.
snap := env.StateDB.Snapshot()
ret, leftOverGas, err := env.Call(vm.AccountRef(sender), addrs.MIPS, input, startingGas, big.NewInt(0))
require.NoError(t, err, "evm should not fail")
require.Len(t, ret, 32, "expecting 32-byte state hash")
// remember state hash, to check it against state
postHash := common.Hash(*(*[32]byte)(ret))
logs := evmState.Logs()
require.Equal(t, 1, len(logs), "expecting a log with post-state")
evmPost := logs[0].Data
require.Equal(t, crypto.Keccak256Hash(evmPost), postHash, "logged state must be accurate")
env.StateDB.RevertToSnapshot(snap)
t.Logf("EVM step took %d gas, and returned stateHash %s", startingGas-leftOverGas, postHash)
// verify the post-state matches.
// TODO: maybe more readable to decode the evmPost state, and do attribute-wise comparison.
uniPost := us.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(uniPost).String(), hexutil.Bytes(evmPost).String(),
"unicorn produced different state than EVM")
}
require.Equal(t, uint32(endAddr), state.PC, "must reach end")
// inspect test result
done, result := state.Memory.GetMemory(baseAddrEnd+4), state.Memory.GetMemory(baseAddrEnd+8)
require.Equal(t, done, uint32(1), "must be done")
require.Equal(t, result, uint32(1), "must have success result")
})
}
}
func TestHelloEVM(t *testing.T) {
contracts, addrs := testContractsSetup(t)
var tracer vm.EVMLogger // no-tracer by default, but see SourceMapTracer and MarkdownTracer
//tracer = SourceMapTracer(t, contracts, addrs)
sender := common.Address{0x13, 0x37}
elfProgram, err := elf.Open("../example/bin/hello.elf")
require.NoError(t, err, "open ELF file")
state, err := LoadELF(elfProgram)
require.NoError(t, err, "load ELF into state")
err = PatchGo(elfProgram, state)
require.NoError(t, err, "apply Go runtime patches")
require.NoError(t, PatchStack(state), "add initial stack")
var stdOutBuf, stdErrBuf bytes.Buffer
us := NewInstrumentedState(state, nil, io.MultiWriter(&stdOutBuf, os.Stdout), io.MultiWriter(&stdErrBuf, os.Stderr))
env, evmState := NewEVMEnv(contracts, addrs)
env.Config.Tracer = tracer
start := time.Now()
for i := 0; i < 400_000; i++ {
if us.state.Exited {
break
}
insn := state.Memory.GetMemory(state.PC)
if i%1000 == 0 { // avoid spamming test logs, we are executing many steps
t.Logf("step: %4d pc: 0x%08x insn: 0x%08x", state.Step, state.PC, insn)
}
stepWitness, err := us.Step(true)
require.NoError(t, err)
input := stepWitness.EncodeStepInput()
startingGas := uint64(30_000_000)
// we take a snapshot so we can clean up the state, and isolate the logs of this instruction run.
snap := env.StateDB.Snapshot()
ret, leftOverGas, err := env.Call(vm.AccountRef(sender), addrs.MIPS, input, startingGas, big.NewInt(0))
require.NoErrorf(t, err, "evm should not fail, took %d gas", startingGas-leftOverGas)
require.Len(t, ret, 32, "expecting 32-byte state hash")
// remember state hash, to check it against state
postHash := common.Hash(*(*[32]byte)(ret))
logs := evmState.Logs()
require.Equal(t, 1, len(logs), "expecting a log with post-state")
evmPost := logs[0].Data
require.Equal(t, crypto.Keccak256Hash(evmPost), postHash, "logged state must be accurate")
env.StateDB.RevertToSnapshot(snap)
//t.Logf("EVM step took %d gas, and returned stateHash %s", startingGas-leftOverGas, postHash)
// verify the post-state matches.
// TODO: maybe more readable to decode the evmPost state, and do attribute-wise comparison.
uniPost := us.state.EncodeWitness()
require.Equal(t, hexutil.Bytes(uniPost).String(), hexutil.Bytes(evmPost).String(),
"unicorn produced different state than EVM")
}
end := time.Now()
delta := end.Sub(start)
t.Logf("test took %s, %d instructions, %s per instruction", delta, state.Step, delta/time.Duration(state.Step))
require.True(t, state.Exited, "must complete program")
require.Equal(t, uint8(0), state.ExitCode, "exit with 0")
require.Equal(t, "hello world!\n", stdOutBuf.String(), "stdout says hello")
require.Equal(t, "", stdErrBuf.String(), "stderr silent")
}
func TestClaimEVM(t *testing.T) {
contracts, addrs := testContractsSetup(t)
var tracer vm.EVMLogger // no-tracer by default, but see SourceMapTracer and MarkdownTracer
//tracer = SourceMapTracer(t, contracts, addrs)
elfProgram, err := elf.Open("../example/bin/claim.elf")
require.NoError(t, err, "open ELF file")
state, err := LoadELF(elfProgram)
require.NoError(t, err, "load ELF into state")
err = PatchGo(elfProgram, state)
require.NoError(t, err, "apply Go runtime patches")
require.NoError(t, PatchStack(state), "add initial stack")
oracle, expectedStdOut, expectedStdErr := claimTestOracle(t)
var stdOutBuf, stdErrBuf bytes.Buffer
us := NewInstrumentedState(state, oracle, io.MultiWriter(&stdOutBuf, os.Stdout), io.MultiWriter(&stdErrBuf, os.Stderr))
env, evmState := NewEVMEnv(contracts, addrs)
env.Config.Tracer = tracer
for i := 0; i < 2000_000; i++ {
if us.state.Exited {
break
}
insn := state.Memory.GetMemory(state.PC)
if i%1000 == 0 { // avoid spamming test logs, we are executing many steps
t.Logf("step: %4d pc: 0x%08x insn: 0x%08x", state.Step, state.PC, insn)
}
stepWitness, err := us.Step(true)
require.NoError(t, err)
input := stepWitness.EncodeStepInput()
startingGas := uint64(30_000_000)
// we take a snapshot so we can clean up the state, and isolate the logs of this instruction run.
snap := env.StateDB.Snapshot()
// prepare pre-image oracle data, if any
if stepWitness.HasPreimage() {
poInput, err := stepWitness.EncodePreimageOracleInput()
require.NoError(t, err, "encode preimage oracle input")
_, leftOverGas, err := env.Call(vm.AccountRef(addrs.Sender), addrs.Oracle, poInput, startingGas, big.NewInt(0))
require.NoErrorf(t, err, "evm should not fail, took %d gas", startingGas-leftOverGas)
}
ret, leftOverGas, err := env.Call(vm.AccountRef(addrs.Sender), addrs.MIPS, input, startingGas, big.NewInt(0))
require.NoErrorf(t, err, "evm should not fail, took %d gas", startingGas-leftOverGas)
require.Len(t, ret, 32, "expecting 32-byte state hash")
// remember state hash, to check it against state
postHash := common.Hash(*(*[32]byte)(ret))
logs := evmState.Logs()
require.Equal(t, 1, len(logs), "expecting a log with post-state")
evmPost := logs[0].Data
require.Equal(t, crypto.Keccak256Hash(evmPost), postHash, "logged state must be accurate")
env.StateDB.RevertToSnapshot(snap)
}
require.True(t, state.Exited, "must complete program")
require.Equal(t, uint8(0), state.ExitCode, "exit with 0")
require.Equal(t, expectedStdOut, stdOutBuf.String(), "stdout")
require.Equal(t, expectedStdErr, stdErrBuf.String(), "stderr")
}
package mipsevm
import (
"io"
)
type PreimageOracle interface {
Hint(v []byte)
GetPreimage(k [32]byte) []byte
}
type InstrumentedState struct {
state *State
stdOut io.Writer
stdErr io.Writer
lastMemAccess uint32
memProofEnabled bool
memProof [28 * 32]byte
preimageOracle PreimageOracle
// cached pre-image data, including 8 byte length prefix
lastPreimage []byte
// key for above preimage
lastPreimageKey [32]byte
// offset we last read from, or max uint32 if nothing is read this step
lastPreimageOffset uint32
}
const (
fdStdin = 0
fdStdout = 1
fdStderr = 2
fdHintRead = 3
fdHintWrite = 4
fdPreimageRead = 5
fdPreimageWrite = 6
)
const (
MipsEBADF = 0x9
MipsEINVAL = 0x16
)
func NewInstrumentedState(state *State, po PreimageOracle, stdOut, stdErr io.Writer) *InstrumentedState {
return &InstrumentedState{
state: state,
stdOut: stdOut,
stdErr: stdErr,
preimageOracle: po,
}
}
func (m *InstrumentedState) Step(proof bool) (wit *StepWitness, err error) {
m.memProofEnabled = proof
m.lastMemAccess = ^uint32(0)
m.lastPreimageOffset = ^uint32(0)
if proof {
insnProof := m.state.Memory.MerkleProof(m.state.PC)
wit = &StepWitness{
State: m.state.EncodeWitness(),
MemProof: insnProof[:],
}
}
err = m.mipsStep()
if err != nil {
return nil, err
}
if proof {
wit.MemProof = append(wit.MemProof, m.memProof[:]...)
if m.lastPreimageOffset != ^uint32(0) {
wit.PreimageOffset = m.lastPreimageOffset
wit.PreimageKey = m.lastPreimageKey
wit.PreimageValue = m.lastPreimage
}
}
return
}
package mipsevm
import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/log"
)
// LoggingWriter is a simple util to wrap a logger,
// and expose an io Writer interface,
// for the program running within the VM to write to.
type LoggingWriter struct {
Name string
Log log.Logger
}
func logAsText(b string) bool {
for _, c := range b {
if (c < 0x20 || c >= 0x7F) && (c != '\n' && c != '\t') {
return false
}
}
return true
}
func (lw *LoggingWriter) Write(b []byte) (int, error) {
t := string(b)
if logAsText(t) {
lw.Log.Info("", "text", t)
} else {
lw.Log.Info("", "data", hexutil.Bytes(b))
}
return len(b), nil
}
package mipsevm
import (
"encoding/binary"
"encoding/json"
"fmt"
"io"
"math/bits"
"sort"
"github.com/ethereum/go-ethereum/crypto"
)
// Note: 2**12 = 4 KiB, the minimum page-size in Unicorn for mmap
// as well as the Go runtime min phys page size.
const (
PageAddrSize = 12
PageKeySize = 32 - PageAddrSize
PageSize = 1 << PageAddrSize
PageAddrMask = PageSize - 1
MaxPageCount = 1 << PageKeySize
PageKeyMask = MaxPageCount - 1
)
func HashPair(left, right [32]byte) [32]byte {
out := crypto.Keccak256Hash(left[:], right[:])
//fmt.Printf("0x%x 0x%x -> 0x%x\n", left, right, out)
return out
}
var zeroHashes = func() [256][32]byte {
// empty parts of the tree are all zero. Precompute the hash of each full-zero range sub-tree level.
var out [256][32]byte
for i := 1; i < 256; i++ {
out[i] = HashPair(out[i-1], out[i-1])
}
return out
}()
type Memory struct {
// generalized index -> merkle root or nil if invalidated
nodes map[uint64]*[32]byte
// pageIndex -> cached page
pages map[uint32]*CachedPage
// Note: since we don't de-alloc pages, we don't do ref-counting.
// Once a page exists, it doesn't leave memory
// two caches: we often read instructions from one page, and do memory things with another page.
// this prevents map lookups each instruction
lastPageKeys [2]uint32
lastPage [2]*CachedPage
}
func NewMemory() *Memory {
return &Memory{
nodes: make(map[uint64]*[32]byte),
pages: make(map[uint32]*CachedPage),
lastPageKeys: [2]uint32{^uint32(0), ^uint32(0)}, // default to invalid keys, to not match any pages
}
}
func (m *Memory) PageCount() int {
return len(m.pages)
}
func (m *Memory) ForEachPage(fn func(pageIndex uint32, page *Page) error) error {
for pageIndex, cachedPage := range m.pages {
if err := fn(pageIndex, cachedPage.Data); err != nil {
return err
}
}
return nil
}
func (m *Memory) Invalidate(addr uint32) {
// addr must be aligned to 4 bytes
if addr&0x3 != 0 {
panic(fmt.Errorf("unaligned memory access: %x", addr))
}
// find page, and invalidate addr within it
if p, ok := m.pageLookup(addr >> PageAddrSize); ok {
prevValid := p.Ok[1]
p.Invalidate(addr & PageAddrMask)
if !prevValid { // if the page was already invalid before, then nodes to mem-root will also still be.
return
}
} else { // no page? nothing to invalidate
return
}
// find the gindex of the first page covering the address
gindex := ((uint64(1) << 32) | uint64(addr)) >> PageAddrSize
for gindex > 0 {
m.nodes[gindex] = nil
gindex >>= 1
}
}
func (m *Memory) MerkleizeSubtree(gindex uint64) [32]byte {
l := uint64(bits.Len64(gindex))
if l > 28 {
panic("gindex too deep")
}
if l > PageKeySize {
depthIntoPage := l - 1 - PageKeySize
pageIndex := (gindex >> depthIntoPage) & PageKeyMask
if p, ok := m.pages[uint32(pageIndex)]; ok {
pageGindex := (1 << depthIntoPage) | (gindex & ((1 << depthIntoPage) - 1))
return p.MerkleizeSubtree(pageGindex)
} else {
return zeroHashes[28-l] // page does not exist
}
}
if l > PageKeySize+1 {
panic("cannot jump into intermediate node of page")
}
n, ok := m.nodes[gindex]
if !ok {
// if the node doesn't exist, the whole sub-tree is zeroed
return zeroHashes[28-l]
}
if n != nil {
return *n
}
left := m.MerkleizeSubtree(gindex << 1)
right := m.MerkleizeSubtree((gindex << 1) | 1)
r := HashPair(left, right)
m.nodes[gindex] = &r
return r
}
func (m *Memory) MerkleProof(addr uint32) (out [28 * 32]byte) {
proof := m.traverseBranch(1, addr, 0)
// encode the proof
for i := 0; i < 28; i++ {
copy(out[i*32:(i+1)*32], proof[i][:])
}
return out
}
func (m *Memory) traverseBranch(parent uint64, addr uint32, depth uint8) (proof [][32]byte) {
if depth == 32-5 {
proof = make([][32]byte, 0, 32-5+1)
proof = append(proof, m.MerkleizeSubtree(parent))
return
}
if depth > 32-5 {
panic("traversed too deep")
}
self := parent << 1
sibling := self | 1
if addr&(1<<(31-depth)) != 0 {
self, sibling = sibling, self
}
proof = m.traverseBranch(self, addr, depth+1)
siblingNode := m.MerkleizeSubtree(sibling)
proof = append(proof, siblingNode)
return
}
func (m *Memory) MerkleRoot() [32]byte {
return m.MerkleizeSubtree(1)
}
func (m *Memory) pageLookup(pageIndex uint32) (*CachedPage, bool) {
// hit caches
if pageIndex == m.lastPageKeys[0] {
return m.lastPage[0], true
}
if pageIndex == m.lastPageKeys[1] {
return m.lastPage[1], true
}
p, ok := m.pages[pageIndex]
// only cache existing pages.
if ok {
m.lastPageKeys[1] = m.lastPageKeys[0]
m.lastPage[1] = m.lastPage[0]
m.lastPageKeys[0] = pageIndex
m.lastPage[0] = p
}
return p, ok
}
func (m *Memory) SetMemory(addr uint32, v uint32) {
// addr must be aligned to 4 bytes
if addr&0x3 != 0 {
panic(fmt.Errorf("unaligned memory access: %x", addr))
}
pageIndex := addr >> PageAddrSize
pageAddr := addr & PageAddrMask
p, ok := m.pageLookup(pageIndex)
if !ok {
// allocate the page if we have not already.
// Go may mmap relatively large ranges, but we only allocate the pages just in time.
p = m.AllocPage(pageIndex)
} else {
m.Invalidate(addr) // invalidate this branch of memory, now that the value changed
}
binary.BigEndian.PutUint32(p.Data[pageAddr:pageAddr+4], v)
}
func (m *Memory) GetMemory(addr uint32) uint32 {
// addr must be aligned to 4 bytes
if addr&0x3 != 0 {
panic(fmt.Errorf("unaligned memory access: %x", addr))
}
p, ok := m.pageLookup(addr >> PageAddrSize)
if !ok {
return 0
}
pageAddr := addr & PageAddrMask
return binary.BigEndian.Uint32(p.Data[pageAddr : pageAddr+4])
}
func (m *Memory) AllocPage(pageIndex uint32) *CachedPage {
p := &CachedPage{Data: new(Page)}
m.pages[pageIndex] = p
// make nodes to root
k := (1 << PageKeySize) | uint64(pageIndex)
for k > 0 {
m.nodes[k] = nil
k >>= 1
}
return p
}
type pageEntry struct {
Index uint32 `json:"index"`
Data *Page `json:"data"`
}
func (m *Memory) MarshalJSON() ([]byte, error) { // nosemgrep
pages := make([]pageEntry, 0, len(m.pages))
for k, p := range m.pages {
pages = append(pages, pageEntry{
Index: k,
Data: p.Data,
})
}
sort.Slice(pages, func(i, j int) bool {
return pages[i].Index < pages[j].Index
})
return json.Marshal(pages)
}
func (m *Memory) UnmarshalJSON(data []byte) error {
var pages []pageEntry
if err := json.Unmarshal(data, &pages); err != nil {
return err
}
m.nodes = make(map[uint64]*[32]byte)
m.pages = make(map[uint32]*CachedPage)
m.lastPageKeys = [2]uint32{^uint32(0), ^uint32(0)}
m.lastPage = [2]*CachedPage{nil, nil}
for i, p := range pages {
if _, ok := m.pages[p.Index]; ok {
return fmt.Errorf("cannot load duplicate page, entry %d, page index %d", i, p.Index)
}
m.AllocPage(p.Index).Data = p.Data
}
return nil
}
func (m *Memory) SetMemoryRange(addr uint32, r io.Reader) error {
for {
pageIndex := addr >> PageAddrSize
pageAddr := addr & PageAddrMask
p, ok := m.pageLookup(pageIndex)
if !ok {
p = m.AllocPage(pageIndex)
}
p.InvalidateFull()
n, err := r.Read(p.Data[pageAddr:])
if err != nil {
if err == io.EOF {
return nil
}
return err
}
addr += uint32(n)
}
}
type memReader struct {
m *Memory
addr uint32
count uint32
}
func (r *memReader) Read(dest []byte) (n int, err error) {
if r.count == 0 {
return 0, io.EOF
}
// Keep iterating over memory until we have all our data.
// It may wrap around the address range, and may not be aligned
endAddr := r.addr + r.count
pageIndex := r.addr >> PageAddrSize
start := r.addr & PageAddrMask
end := uint32(PageSize)
if pageIndex == (endAddr >> PageAddrSize) {
end = endAddr & PageAddrMask
}
p, ok := r.m.pageLookup(pageIndex)
if ok {
n = copy(dest, p.Data[start:end])
} else {
n = copy(dest, make([]byte, end-start)) // default to zeroes
}
r.addr += uint32(n)
r.count -= uint32(n)
return n, nil
}
func (m *Memory) ReadMemoryRange(addr uint32, count uint32) io.Reader {
return &memReader{m: m, addr: addr, count: count}
}
func (m *Memory) Usage() string {
total := uint64(len(m.pages)) * PageSize
const unit = 1024
if total < unit {
return fmt.Sprintf("%d B", total)
}
div, exp := uint64(unit), 0
for n := total / unit; n >= unit; n /= unit {
div *= unit
exp++
}
// KiB, MiB, GiB, TiB, ...
return fmt.Sprintf("%.1f %ciB", float64(total)/float64(div), "KMGTPE"[exp])
}
package mipsevm
import (
"bytes"
"crypto/rand"
"encoding/binary"
"encoding/json"
"io"
"strings"
"testing"
"github.com/stretchr/testify/require"
)
func TestMemoryMerkleProof(t *testing.T) {
t.Run("nearly empty tree", func(t *testing.T) {
m := NewMemory()
m.SetMemory(0x10000, 0xaabbccdd)
proof := m.MerkleProof(0x10000)
require.Equal(t, uint32(0xaabbccdd), binary.BigEndian.Uint32(proof[:4]))
for i := 0; i < 32-5; i++ {
require.Equal(t, zeroHashes[i][:], proof[32+i*32:32+i*32+32], "empty siblings")
}
})
t.Run("fuller tree", func(t *testing.T) {
m := NewMemory()
m.SetMemory(0x10000, 0xaabbccdd)
m.SetMemory(0x80004, 42)
m.SetMemory(0x13370000, 123)
root := m.MerkleRoot()
proof := m.MerkleProof(0x80004)
require.Equal(t, uint32(42), binary.BigEndian.Uint32(proof[4:8]))
node := *(*[32]byte)(proof[:32])
path := uint32(0x80004) >> 5
for i := 32; i < len(proof); i += 32 {
sib := *(*[32]byte)(proof[i : i+32])
if path&1 != 0 {
node = HashPair(sib, node)
} else {
node = HashPair(node, sib)
}
path >>= 1
}
require.Equal(t, root, node, "proof must verify")
})
}
func TestMemoryMerkleRoot(t *testing.T) {
t.Run("empty", func(t *testing.T) {
m := NewMemory()
root := m.MerkleRoot()
require.Equal(t, zeroHashes[32-5], root, "fully zeroed memory should have expected zero hash")
})
t.Run("empty page", func(t *testing.T) {
m := NewMemory()
m.SetMemory(0xF000, 0)
root := m.MerkleRoot()
require.Equal(t, zeroHashes[32-5], root, "fully zeroed memory should have expected zero hash")
})
t.Run("single page", func(t *testing.T) {
m := NewMemory()
m.SetMemory(0xF000, 1)
root := m.MerkleRoot()
require.NotEqual(t, zeroHashes[32-5], root, "non-zero memory")
})
t.Run("repeat zero", func(t *testing.T) {
m := NewMemory()
m.SetMemory(0xF000, 0)
m.SetMemory(0xF004, 0)
root := m.MerkleRoot()
require.Equal(t, zeroHashes[32-5], root, "zero still")
})
t.Run("two empty pages", func(t *testing.T) {
m := NewMemory()
m.SetMemory(PageSize*3, 0)
m.SetMemory(PageSize*10, 0)
root := m.MerkleRoot()
require.Equal(t, zeroHashes[32-5], root, "zero still")
})
t.Run("random few pages", func(t *testing.T) {
m := NewMemory()
m.SetMemory(PageSize*3, 1)
m.SetMemory(PageSize*5, 42)
m.SetMemory(PageSize*6, 123)
p3 := m.MerkleizeSubtree((1 << PageKeySize) | 3)
p5 := m.MerkleizeSubtree((1 << PageKeySize) | 5)
p6 := m.MerkleizeSubtree((1 << PageKeySize) | 6)
z := zeroHashes[PageAddrSize-5]
r1 := HashPair(
HashPair(
HashPair(z, z), // 0,1
HashPair(z, p3), // 2,3
),
HashPair(
HashPair(z, p5), // 4,5
HashPair(p6, z), // 6,7
),
)
r2 := m.MerkleizeSubtree(1 << (PageKeySize - 3))
require.Equal(t, r1, r2, "expecting manual page combination to match subtree merkle func")
})
t.Run("invalidate page", func(t *testing.T) {
m := NewMemory()
m.SetMemory(0xF000, 0)
require.Equal(t, zeroHashes[32-5], m.MerkleRoot(), "zero at first")
m.SetMemory(0xF004, 1)
require.NotEqual(t, zeroHashes[32-5], m.MerkleRoot(), "non-zero")
m.SetMemory(0xF004, 0)
require.Equal(t, zeroHashes[32-5], m.MerkleRoot(), "zero again")
})
}
func TestMemoryReadWrite(t *testing.T) {
t.Run("large random", func(t *testing.T) {
m := NewMemory()
data := make([]byte, 20_000)
_, err := rand.Read(data[:])
require.NoError(t, err)
require.NoError(t, m.SetMemoryRange(0, bytes.NewReader(data)))
for _, i := range []uint32{0, 4, 1000, 20_000 - 4} {
v := m.GetMemory(i)
expected := binary.BigEndian.Uint32(data[i : i+4])
require.Equalf(t, expected, v, "read at %d", i)
}
})
t.Run("repeat range", func(t *testing.T) {
m := NewMemory()
data := []byte(strings.Repeat("under the big bright yellow sun ", 40))
require.NoError(t, m.SetMemoryRange(0x1337, bytes.NewReader(data)))
res, err := io.ReadAll(m.ReadMemoryRange(0x1337-10, uint32(len(data)+20)))
require.NoError(t, err)
require.Equal(t, make([]byte, 10), res[:10], "empty start")
require.Equal(t, data, res[10:len(res)-10], "result")
require.Equal(t, make([]byte, 10), res[len(res)-10:], "empty end")
})
t.Run("read-write", func(t *testing.T) {
m := NewMemory()
m.SetMemory(12, 0xAABBCCDD)
require.Equal(t, uint32(0xAABBCCDD), m.GetMemory(12))
m.SetMemory(12, 0xAABB1CDD)
require.Equal(t, uint32(0xAABB1CDD), m.GetMemory(12))
})
t.Run("unaligned read", func(t *testing.T) {
m := NewMemory()
m.SetMemory(12, 0xAABBCCDD)
m.SetMemory(16, 0x11223344)
require.Panics(t, func() {
m.GetMemory(13)
})
require.Panics(t, func() {
m.GetMemory(14)
})
require.Panics(t, func() {
m.GetMemory(15)
})
require.Equal(t, uint32(0x11223344), m.GetMemory(16))
require.Equal(t, uint32(0), m.GetMemory(20))
require.Equal(t, uint32(0xAABBCCDD), m.GetMemory(12))
})
t.Run("unaligned write", func(t *testing.T) {
m := NewMemory()
m.SetMemory(12, 0xAABBCCDD)
require.Panics(t, func() {
m.SetMemory(13, 0x11223344)
})
require.Panics(t, func() {
m.SetMemory(14, 0x11223344)
})
require.Panics(t, func() {
m.SetMemory(15, 0x11223344)
})
require.Equal(t, uint32(0xAABBCCDD), m.GetMemory(12))
})
}
func TestMemoryJSON(t *testing.T) {
m := NewMemory()
m.SetMemory(8, 123)
dat, err := json.Marshal(m)
require.NoError(t, err)
var res Memory
require.NoError(t, json.Unmarshal(dat, &res))
require.Equal(t, uint32(123), res.GetMemory(8))
}
package mipsevm
import (
"debug/elf"
"fmt"
"sort"
)
type Symbol struct {
Name string `json:"name"`
Start uint32 `json:"start"`
Size uint32 `json:"size"`
}
type Metadata struct {
Symbols []Symbol `json:"symbols"`
}
func MakeMetadata(elfProgram *elf.File) (*Metadata, error) {
syms, err := elfProgram.Symbols()
if err != nil {
return nil, fmt.Errorf("failed to load symbols table: %w", err)
}
// Make sure the table is sorted, Go outputs mostly sorted data, except some internal functions
sort.Slice(syms, func(i, j int) bool {
return syms[i].Value < syms[j].Value
})
out := &Metadata{Symbols: make([]Symbol, len(syms))}
for i, s := range syms {
out.Symbols[i] = Symbol{Name: s.Name, Start: uint32(s.Value), Size: uint32(s.Size)}
}
return out, nil
}
func (m *Metadata) LookupSymbol(addr uint32) string {
if len(m.Symbols) == 0 {
return "!unknown"
}
// find first symbol with higher start. Or n if no such symbol exists
i := sort.Search(len(m.Symbols), func(i int) bool {
return m.Symbols[i].Start > addr
})
if i == 0 {
return "!start"
}
out := &m.Symbols[i-1]
if out.Start+out.Size < addr { // addr may be pointing to a gap between symbols
return "!gap"
}
return out.Name
}
func (m *Metadata) SymbolMatcher(name string) func(addr uint32) bool {
for _, s := range m.Symbols {
if s.Name == name {
start := s.Start
end := s.Start + s.Size
return func(addr uint32) bool {
return addr >= start && addr < end
}
}
}
return func(addr uint32) bool {
return false
}
}
// HexU32 to lazy-format integer attributes for logging
type HexU32 uint32
func (v HexU32) String() string {
return fmt.Sprintf("%08x", uint32(v))
}
func (v HexU32) MarshalText() ([]byte, error) {
return []byte(v.String()), nil
}
package mipsevm
import (
"encoding/binary"
"fmt"
"io"
)
func (m *InstrumentedState) readPreimage(key [32]byte, offset uint32) (dat [32]byte, datLen uint32) {
preimage := m.lastPreimage
if key != m.lastPreimageKey {
m.lastPreimageKey = key
data := m.preimageOracle.GetPreimage(key)
// add the length prefix
preimage = make([]byte, 0, 8+len(data))
preimage = binary.BigEndian.AppendUint64(preimage, uint64(len(data)))
preimage = append(preimage, data...)
m.lastPreimage = preimage
}
m.lastPreimageOffset = offset
datLen = uint32(copy(dat[:], preimage[offset:]))
return
}
func (m *InstrumentedState) trackMemAccess(effAddr uint32) {
if m.memProofEnabled && m.lastMemAccess != effAddr {
if m.lastMemAccess != ^uint32(0) {
panic(fmt.Errorf("unexpected different mem access at %08x, already have access at %08x buffered", effAddr, m.lastMemAccess))
}
m.lastMemAccess = effAddr
m.memProof = m.state.Memory.MerkleProof(effAddr)
}
}
func (m *InstrumentedState) handleSyscall() error {
syscallNum := m.state.Registers[2] // v0
v0 := uint32(0)
v1 := uint32(0)
a0 := m.state.Registers[4]
a1 := m.state.Registers[5]
a2 := m.state.Registers[6]
//fmt.Printf("syscall: %d\n", syscallNum)
switch syscallNum {
case 4090: // mmap
sz := a1
if sz&PageAddrMask != 0 { // adjust size to align with page size
sz += PageSize - (sz & PageAddrMask)
}
if a0 == 0 {
v0 = m.state.Heap
//fmt.Printf("mmap heap 0x%x size 0x%x\n", v0, sz)
m.state.Heap += sz
} else {
v0 = a0
//fmt.Printf("mmap hint 0x%x size 0x%x\n", v0, sz)
}
// Go does this thing where it first gets memory with PROT_NONE,
// and then mmaps with a hint with prot=3 (PROT_READ|WRITE).
// We can ignore the NONE case, to avoid duplicate/overlapping mmap calls to unicorn.
//prot := a2
//if prot != 0 {
// if err := mu.MemMap(uint64(v0), uint64(sz)); err != nil {
// log.Fatalf("mmap fail: %v", err)
// }
//}
case 4045: // brk
v0 = 0x40000000
case 4120: // clone (not supported)
v0 = 1
case 4246: // exit_group
m.state.Exited = true
m.state.ExitCode = uint8(a0)
return nil
case 4003: // read
// args: a0 = fd, a1 = addr, a2 = count
// returns: v0 = read, v1 = err code
switch a0 {
case fdStdin:
// leave v0 and v1 zero: read nothing, no error
case fdPreimageRead: // pre-image oracle
effAddr := a1 & 0xFFffFFfc
m.trackMemAccess(effAddr)
mem := m.state.Memory.GetMemory(effAddr)
dat, datLen := m.readPreimage(m.state.PreimageKey, m.state.PreimageOffset)
//fmt.Printf("reading pre-image data: addr: %08x, offset: %d, datLen: %d, data: %x, key: %s count: %d\n", a1, m.state.PreimageOffset, datLen, dat[:datLen], m.state.PreimageKey, a2)
alignment := a1 & 3
space := 4 - alignment
if space < datLen {
datLen = space
}
if a2 < datLen {
datLen = a2
}
var outMem [4]byte
binary.BigEndian.PutUint32(outMem[:], mem)
copy(outMem[alignment:], dat[:datLen])
m.state.Memory.SetMemory(effAddr, binary.BigEndian.Uint32(outMem[:]))
m.state.PreimageOffset += datLen
v0 = datLen
//fmt.Printf("read %d pre-image bytes, new offset: %d, eff addr: %08x mem: %08x\n", datLen, m.state.PreimageOffset, effAddr, outMem)
case fdHintRead: // hint response
// don't actually read into memory, just say we read it all, we ignore the result anyway
v0 = a2
default:
v0 = 0xFFffFFff
v1 = MipsEBADF
}
case 4004: // write
// args: a0 = fd, a1 = addr, a2 = count
// returns: v0 = written, v1 = err code
switch a0 {
case fdStdout:
_, _ = io.Copy(m.stdOut, m.state.Memory.ReadMemoryRange(a1, a2))
v0 = a2
case fdStderr:
_, _ = io.Copy(m.stdErr, m.state.Memory.ReadMemoryRange(a1, a2))
v0 = a2
case fdHintWrite:
hintData, _ := io.ReadAll(m.state.Memory.ReadMemoryRange(a1, a2))
m.state.LastHint = append(m.state.LastHint, hintData...)
for len(m.state.LastHint) >= 4 { // process while there is enough data to check if there are any hints
hintLen := binary.BigEndian.Uint32(m.state.LastHint[:4])
if hintLen >= uint32(len(m.state.LastHint[4:])) {
hint := m.state.LastHint[4 : 4+hintLen] // without the length prefix
m.state.LastHint = m.state.LastHint[4+hintLen:]
m.preimageOracle.Hint(hint)
} else {
break // stop processing hints if there is incomplete data buffered
}
}
v0 = a2
case fdPreimageWrite:
effAddr := a1 & 0xFFffFFfc
m.trackMemAccess(effAddr)
mem := m.state.Memory.GetMemory(effAddr)
key := m.state.PreimageKey
alignment := a1 & 3
space := 4 - alignment
if space < a2 {
a2 = space
}
copy(key[:], key[a2:])
var tmp [4]byte
binary.BigEndian.PutUint32(tmp[:], mem)
copy(key[32-a2:], tmp[:])
m.state.PreimageKey = key
m.state.PreimageOffset = 0
//fmt.Printf("updating pre-image key: %s\n", m.state.PreimageKey)
v0 = a2
default:
v0 = 0xFFffFFff
v1 = MipsEBADF
}
case 4055: // fcntl
// args: a0 = fd, a1 = cmd
if a1 == 3 { // F_GETFL: get file descriptor flags
switch a0 {
case fdStdin, fdPreimageRead, fdHintRead:
v0 = 0 // O_RDONLY
case fdStdout, fdStderr, fdPreimageWrite, fdHintWrite:
v0 = 1 // O_WRONLY
default:
v0 = 0xFFffFFff
v1 = MipsEBADF
}
} else {
v0 = 0xFFffFFff
v1 = MipsEINVAL // cmd not recognized by this kernel
}
}
m.state.Registers[2] = v0
m.state.Registers[7] = v1
m.state.PC = m.state.NextPC
m.state.NextPC = m.state.NextPC + 4
return nil
}
func (m *InstrumentedState) handleBranch(opcode uint32, insn uint32, rtReg uint32, rs uint32) error {
shouldBranch := false
if opcode == 4 || opcode == 5 { // beq/bne
rt := m.state.Registers[rtReg]
shouldBranch = (rs == rt && opcode == 4) || (rs != rt && opcode == 5)
} else if opcode == 6 {
shouldBranch = int32(rs) <= 0 // blez
} else if opcode == 7 {
shouldBranch = int32(rs) > 0 // bgtz
} else if opcode == 1 {
// regimm
rtv := (insn >> 16) & 0x1F
if rtv == 0 { // bltz
shouldBranch = int32(rs) < 0
}
if rtv == 1 { // bgez
shouldBranch = int32(rs) >= 0
}
}
prevPC := m.state.PC
m.state.PC = m.state.NextPC // execute the delay slot first
if shouldBranch {
m.state.NextPC = prevPC + 4 + (SE(insn&0xFFFF, 16) << 2) // then continue with the instruction the branch jumps to.
} else {
m.state.NextPC = m.state.NextPC + 4 // branch not taken
}
return nil
}
func (m *InstrumentedState) handleHiLo(fun uint32, rs uint32, rt uint32, storeReg uint32) error {
val := uint32(0)
switch fun {
case 0x10: // mfhi
val = m.state.HI
case 0x11: // mthi
m.state.HI = rs
case 0x12: // mflo
val = m.state.LO
case 0x13: // mtlo
m.state.LO = rs
case 0x18: // mult
acc := uint64(int64(int32(rs)) * int64(int32(rt)))
m.state.HI = uint32(acc >> 32)
m.state.LO = uint32(acc)
case 0x19: // multu
acc := uint64(uint64(rs) * uint64(rt))
m.state.HI = uint32(acc >> 32)
m.state.LO = uint32(acc)
case 0x1a: // div
m.state.HI = uint32(int32(rs) % int32(rt))
m.state.LO = uint32(int32(rs) / int32(rt))
case 0x1b: // divu
m.state.HI = rs % rt
m.state.LO = rs / rt
}
if storeReg != 0 {
m.state.Registers[storeReg] = val
}
m.state.PC = m.state.NextPC
m.state.NextPC = m.state.NextPC + 4
return nil
}
func (m *InstrumentedState) handleJump(linkReg uint32, dest uint32) error {
prevPC := m.state.PC
m.state.PC = m.state.NextPC
m.state.NextPC = dest
if linkReg != 0 {
m.state.Registers[linkReg] = prevPC + 8 // set the link-register to the instr after the delay slot instruction.
}
return nil
}
func (m *InstrumentedState) handleRd(storeReg uint32, val uint32, conditional bool) error {
if storeReg >= 32 {
panic("invalid register")
}
if storeReg != 0 && conditional {
m.state.Registers[storeReg] = val
}
m.state.PC = m.state.NextPC
m.state.NextPC = m.state.NextPC + 4
return nil
}
func (m *InstrumentedState) mipsStep() error {
if m.state.Exited {
return nil
}
m.state.Step += 1
// instruction fetch
insn := m.state.Memory.GetMemory(m.state.PC)
opcode := insn >> 26 // 6-bits
// j-type j/jal
if opcode == 2 || opcode == 3 {
// TODO likely bug in original code: MIPS spec says this should be in the "current" region;
// a 256 MB aligned region (i.e. use top 4 bits of branch delay slot (pc+4))
linkReg := uint32(0)
if opcode == 3 {
linkReg = 31
}
return m.handleJump(linkReg, SE(insn&0x03FFFFFF, 26)<<2)
}
// register fetch
rs := uint32(0) // source register 1 value
rt := uint32(0) // source register 2 / temp value
rtReg := (insn >> 16) & 0x1F
// R-type or I-type (stores rt)
rs = m.state.Registers[(insn>>21)&0x1F]
rdReg := rtReg
if opcode == 0 || opcode == 0x1c {
// R-type (stores rd)
rt = m.state.Registers[rtReg]
rdReg = (insn >> 11) & 0x1F
} else if opcode < 0x20 {
// rt is SignExtImm
// don't sign extend for andi, ori, xori
if opcode == 0xC || opcode == 0xD || opcode == 0xe {
// ZeroExtImm
rt = insn & 0xFFFF
} else {
// SignExtImm
rt = SE(insn&0xFFFF, 16)
}
} else if opcode >= 0x28 || opcode == 0x22 || opcode == 0x26 {
// store rt value with store
rt = m.state.Registers[rtReg]
// store actual rt with lwl and lwr
rdReg = rtReg
}
if (opcode >= 4 && opcode < 8) || opcode == 1 {
return m.handleBranch(opcode, insn, rtReg, rs)
}
storeAddr := uint32(0xFF_FF_FF_FF)
// memory fetch (all I-type)
// we do the load for stores also
mem := uint32(0)
if opcode >= 0x20 {
// M[R[rs]+SignExtImm]
rs += SE(insn&0xFFFF, 16)
addr := rs & 0xFFFFFFFC
m.trackMemAccess(addr)
mem = m.state.Memory.GetMemory(addr)
if opcode >= 0x28 && opcode != 0x30 {
// store
storeAddr = addr
// store opcodes don't write back to a register
rdReg = 0
}
}
// ALU
val := execute(insn, rs, rt, mem)
fun := insn & 0x3f // 6-bits
if opcode == 0 && fun >= 8 && fun < 0x1c {
if fun == 8 || fun == 9 { // jr/jalr
linkReg := uint32(0)
if fun == 9 {
linkReg = rdReg
}
return m.handleJump(linkReg, rs)
}
if fun == 0xa { // movz
return m.handleRd(rdReg, rs, rt == 0)
}
if fun == 0xb { // movn
return m.handleRd(rdReg, rs, rt != 0)
}
// syscall (can read and write)
if fun == 0xC {
return m.handleSyscall()
}
// lo and hi registers
// can write back
if fun >= 0x10 && fun < 0x1c {
return m.handleHiLo(fun, rs, rt, rdReg)
}
}
// stupid sc, write a 1 to rt
if opcode == 0x38 && rtReg != 0 {
m.state.Registers[rtReg] = 1
}
// write memory
if storeAddr != 0xFF_FF_FF_FF {
m.trackMemAccess(storeAddr)
m.state.Memory.SetMemory(storeAddr, val)
}
// write back the value to destination register
return m.handleRd(rdReg, val, true)
}
func execute(insn uint32, rs uint32, rt uint32, mem uint32) uint32 {
opcode := insn >> 26 // 6-bits
fun := insn & 0x3f // 6-bits
// TODO(CLI-4136): deref the immed into a register
if opcode < 0x20 {
// transform ArithLogI
// TODO(CLI-4136): replace with table
if opcode >= 8 && opcode < 0xF {
switch opcode {
case 8:
fun = 0x20 // addi
case 9:
fun = 0x21 // addiu
case 0xA:
fun = 0x2A // slti
case 0xB:
fun = 0x2B // sltiu
case 0xC:
fun = 0x24 // andi
case 0xD:
fun = 0x25 // ori
case 0xE:
fun = 0x26 // xori
}
opcode = 0
}
// 0 is opcode SPECIAL
if opcode == 0 {
shamt := (insn >> 6) & 0x1F
if fun < 0x20 {
switch {
case fun >= 0x08:
return rs // jr/jalr/div + others
case fun == 0x00:
return rt << shamt // sll
case fun == 0x02:
return rt >> shamt // srl
case fun == 0x03:
return SE(rt>>shamt, 32-shamt) // sra
case fun == 0x04:
return rt << (rs & 0x1F) // sllv
case fun == 0x06:
return rt >> (rs & 0x1F) // srlv
case fun == 0x07:
return SE(rt>>rs, 32-rs) // srav
}
}
// 0x10-0x13 = mfhi, mthi, mflo, mtlo
// R-type (ArithLog)
switch fun {
case 0x20, 0x21:
return rs + rt // add or addu
case 0x22, 0x23:
return rs - rt // sub or subu
case 0x24:
return rs & rt // and
case 0x25:
return rs | rt // or
case 0x26:
return rs ^ rt // xor
case 0x27:
return ^(rs | rt) // nor
case 0x2A:
if int32(rs) < int32(rt) {
return 1 // slt
} else {
return 0
}
case 0x2B:
if rs < rt {
return 1 // sltu
} else {
return 0
}
}
} else if opcode == 0xF {
return rt << 16 // lui
} else if opcode == 0x1C { // SPECIAL2
if fun == 2 { // mul
return uint32(int32(rs) * int32(rt))
}
if fun == 0x20 || fun == 0x21 { // clo
if fun == 0x20 {
rs = ^rs
}
i := uint32(0)
for ; rs&0x80000000 != 0; i++ {
rs <<= 1
}
return i
}
}
} else if opcode < 0x28 {
switch opcode {
case 0x20: // lb
return SE((mem>>(24-(rs&3)*8))&0xFF, 8)
case 0x21: // lh
return SE((mem>>(16-(rs&2)*8))&0xFFFF, 16)
case 0x22: // lwl
val := mem << ((rs & 3) * 8)
mask := uint32(0xFFFFFFFF) << ((rs & 3) * 8)
return (rt & ^mask) | val
case 0x23: // lw
return mem
case 0x24: // lbu
return (mem >> (24 - (rs&3)*8)) & 0xFF
case 0x25: // lhu
return (mem >> (16 - (rs&2)*8)) & 0xFFFF
case 0x26: // lwr
val := mem >> (24 - (rs&3)*8)
mask := uint32(0xFFFFFFFF) >> (24 - (rs&3)*8)
return (rt & ^mask) | val
}
} else if opcode == 0x28 { // sb
val := (rt & 0xFF) << (24 - (rs&3)*8)
mask := 0xFFFFFFFF ^ uint32(0xFF<<(24-(rs&3)*8))
return (mem & mask) | val
} else if opcode == 0x29 { // sh
val := (rt & 0xFFFF) << (16 - (rs&2)*8)
mask := 0xFFFFFFFF ^ uint32(0xFFFF<<(16-(rs&2)*8))
return (mem & mask) | val
} else if opcode == 0x2a { // swl
val := rt >> ((rs & 3) * 8)
mask := uint32(0xFFFFFFFF) >> ((rs & 3) * 8)
return (mem & ^mask) | val
} else if opcode == 0x2b { // sw
return rt
} else if opcode == 0x2e { // swr
val := rt << (24 - (rs&3)*8)
mask := uint32(0xFFFFFFFF) << (24 - (rs&3)*8)
return (mem & ^mask) | val
} else if opcode == 0x30 {
return mem // ll
} else if opcode == 0x38 {
return rt // sc
}
panic("invalid instruction")
}
func SE(dat uint32, idx uint32) uint32 {
isSigned := (dat >> (idx - 1)) != 0
signed := ((uint32(1) << (32 - idx)) - 1) << idx
mask := (uint32(1) << idx) - 1
if isSigned {
return dat&mask | signed
} else {
return dat & mask
}
}
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
# OpenMIPS test vectors
Tests from https://github.com/grantae/OpenMIPS/tree/d606b35e9d5260aef20de2a58660c8303a681e9c/software/test/macro/tests
OpenMIPS is licensed LGPLv3 (as seen in the root of the repository), see [`LICENSE`](./LICENSE) file.
Note that some build-system files from 2014/2015 in that repository by the same author are marked as BSD licensed,
but the build-system is not used here.
Requires https://github.com/sergev/LiteBSD/releases/download/tools/gcc-4.8.1-mips-macosx.tgz to build
#!/usr/bin/env python3
import os
import sys
import tempfile
from capstone import *
from elftools.elf.elffile import ELFFile
md = Cs(CS_ARCH_MIPS, CS_MODE_32 + CS_MODE_BIG_ENDIAN)
def maketest(d, out):
with tempfile.NamedTemporaryFile() as nf:
path = "/Users/kafka/fun/mips/mips-gcc-4.8.1/bin/"
print("building", d, "->", out)
# which mips is go
ret = os.system("%s/mips-elf-as -defsym big_endian=1 -march=mips32r2 -o %s %s" % (path, nf.name, d))
assert(ret == 0)
nf.seek(0)
elffile = ELFFile(nf)
#print(elffile)
for sec in elffile.iter_sections():
#print(sec, sec.name, sec.data())
if sec.name == ".test":
with open(out, "wb") as f:
# jump to 0xdead0000 when done
#data = b"\x24\x1f\xde\xad\x00\x1f\xfc\x00" + sec.data()
data = sec.data()
for dd in md.disasm(data, 0):
print(dd)
f.write(data)
if __name__ == "__main__":
os.makedirs("/tmp/mips", exist_ok=True)
if len(sys.argv) > 2:
maketest(sys.argv[1], sys.argv[2])
else:
for d in os.listdir("test/"):
if not d.endswith(".asm"):
continue
maketest("test/"+d, "test/bin/"+(d.replace(".asm", ".bin")))
\ No newline at end of file
###############################################################################
# File : add.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'add' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xffff # A = 0xfffffffd (-3)
ori $t0, 0xfffd
ori $t1, $0, 0x3 # B = 0x3
add $t2, $t0, $t1 # C = A + B = 0
sltiu $v0, $t2, 1 # D = 1 if C == 0
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : addi.asm
# Project : MIPS32 MUX
# Author : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'addi' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xffff # A = 0xfffffffd (-3)
ori $t0, 0xfffd
addi $t1, $t0, 5 # B = A + 5 = 2
addi $t2, $t1, 0xfffe # C = B + -2 = 0
sltiu $v0, $t2, 1 # D = 1 if C == 0
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : addiu.asm
# Project : MIPS32 MUX
# Author : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'addiu' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xffff # A = 0xfffffffd (-3)
ori $t0, 0xfffd
addiu $t1, $t0, 5 # B = A + 5 = 2
addiu $t2, $t1, 0xfffe # C = B + -2 = 0
sltiu $v0, $t2, 1 # D = 1 if C == 0
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : addu.asm
# Project : MIPS32 MUX
# Author : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'addu' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xffff # A = 0xfffffffd (-3)
ori $t0, 0xfffd
ori $t1, $0, 0x3 # B = 0x3
addu $t2, $t0, $t1 # C = A + B = 0
sltiu $v0, $t2, 1 # D = 1 if C == 0
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : and.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'and' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xdeaf # A = 0xdeafbeef
lui $t1, 0xaaaa # B = 0xaaaaaaaa
lui $t2, 0x5555 # C = 0x55555555
ori $t0, 0xbeef
ori $t1, 0xaaaa
ori $t2, 0x5555
and $t3, $t0, $t1 # D = A & B = 0x8aaaaaaa
and $t4, $t2, $t3 # E = B & D = 0
sltiu $v0, $t4, 1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : andi.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'andi' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
ori $t0, $0, 0xcafe # A = 0xcafe
andi $t1, $t0, 0xaaaa # B = A & 0xaaaa = 0x8aaa
andi $t2, $t1, 0x5555 # C = B & 0x5555 = 0
sltiu $v0, $t2, 1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : beq.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'beq' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
ori $t0, $0, 0xcafe
ori $t1, $0, 0xcafe
ori $v0, $0, 0 # The test result starts as a failure
beq $t0, $v0, $finish # No branch
nop
beq $t0, $t1, $target
nop
$finish:
sw $v0, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
j $finish # Early-by-1 branch detection
$target:
nop
ori $v0, $0, 1 # Set the result to pass
beq $0, $0, $finish # Late-by-1 branch detection (result not stored)
nop
j $finish
nop
#### Test code end ####
.end test
###############################################################################
# File : bgez.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'bgez' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xffff
bgez $t0, $finish # No branch
nop
bgez $s1, $target
nop
$finish:
sw $v0, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
j $finish # Early-by-1 branch detection
$target:
nop
ori $v0, $0, 1 # Set the result to pass
bgez $0, $finish # Late-by-1 branch detection (result not stored)
nop
j $finish # Broken branch recovery
nop
#### Test code end ####
.end test
###############################################################################
# File : bgtz.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'bgtz' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
ori $v0, $0, 0 # The test result starts as a failure
lui $t0, 0xffff
bgtz $t0, $finish # No branch
nop
bgtz $s1, $target
nop
$finish:
sw $v0, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
j $finish # Early-by-1 branch detection
$target:
nop
ori $v0, $0, 1 # Set the result to pass
bgtz $s1, $finish # Late-by-1 branch detection (result not stored)
nop
j $finish # Broken branch recovery
nop
#### Test code end ####
.end test
###############################################################################
# File : blez.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'blez' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
ori $v0, $0, 0 # The test result starts as a failure
blez $s1, $finish # No branch
lui $t0, 0xffff
blez $t0, $target
nop
$finish:
sw $v0, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
j $finish # Early-by-1 branch detection
$target:
nop
ori $v0, $0, 1 # Set the result to pass
blez $0, $finish # Late-by-1 branch detection (result not stored)
nop
j $finish
nop
#### Test code end ####
.end test
###############################################################################
# File : bltz.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'bltz' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
ori $v0, $0, 0 # The test result starts as a failure
bltz $0, $finish # No branch
nop
bltz $s1, $finish # No branch
lui $t0, 0xffff
bltz $t0, $target
nop
$finish:
sw $v0, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
j $finish # Early-by-1 branch detection
$target:
nop
ori $v0, $0, 1 # Set the result to pass
bltz $t0, $finish # Late-by-1 branch detection (result not stored)
nop
j $finish # Broken branch recovery
nop
#### Test code end ####
.end test
###############################################################################
# File : bne.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'bne' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
ori $t0, $0, 0xcafe
ori $t1, $0, 0xcafe
ori $v0, $0, 0 # The test result starts as a failure
bne $t0, $t1, $finish # No branch
nop
bne $t0, $v0, $target
nop
$finish:
sw $v0, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
j $finish # Early-by-1 branch detection
$target:
nop
ori $v0, $0, 1 # Set the result to pass
bne $t0, $0, $finish # Late-by-1 branch detection (result not stored)
nop
j $finish
nop
#### Test code end ####
.end test
###############################################################################
# File : clo.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'clo' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t2, 0xffff # 32
ori $t2, 0xffff
lui $t3, 0xffff # 18
ori $t3, 0xc000
lui $t4, 0xf800 # 5
lui $t5, 0xf000 # 4
lui $t6, 0x7fff # 0
ori $t7, $0, 0 # 0
clo $s2, $t2
clo $s3, $t3
clo $s4, $t4
clo $s5, $t5
clo $s6, $t6
clo $s7, $t7
addiu $s2, -32
addiu $s3, -18
addiu $s4, -5
addiu $s5, -4
addiu $s6, 0
addiu $s7, 0
or $v1, $s2, $s3
or $v1, $v1, $s4
or $v1, $v1, $s5
or $v1, $v1, $s6
or $v1, $v1, $s7
sltiu $v0, $v1, 1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : clz.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'clz' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t2, 0xffff # 0
ori $t2, 0xffff
ori $t3, $0, 0x0100 # 23
lui $t4, 0x0700 # 5
lui $t5, 0x0f00 # 4
lui $t6, 0x7fff # 1
ori $t7, $0, 0 # 32
clz $s2, $t2
clz $s3, $t3
clz $s4, $t4
clz $s5, $t5
clz $s6, $t6
clz $s7, $t7
addiu $s2, 0
addiu $s3, -23
addiu $s4, -5
addiu $s5, -4
addiu $s6, -1
addiu $s7, -32
or $v1, $s2, $s3
or $v1, $v1, $s4
or $v1, $v1, $s5
or $v1, $v1, $s6
or $v1, $v1, $s7
sltiu $v0, $v1, 1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : div.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'div' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0x1234
ori $t0, 0x5678
lui $t1, 0xc001
ori $t1, 0xcafe
div $t1, $t0 # 0xfffffffd (q), 0xf69ece66 (r)
mfhi $t2
mflo $t3
lui $t4, 0xf69e
ori $t4, 0xce66
lui $t5, 0xffff
ori $t5, 0xfffd
subu $t6, $t2, $t4
subu $t7, $t3, $t5
sltiu $v0, $t6, 1
sltiu $v1, $t7, 1
and $v0, $v0, $v1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : divu.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'divu' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0x1234
ori $t0, 0x5678
lui $t1, 0xc001
ori $t1, 0xcafe
divu $t1, $t0 # 0xa (q), 0x09f66a4e (r)
mfhi $t2
mflo $t3
lui $t4, 0x09f6
ori $t4, 0x6a4e
lui $t5, 0x0000
ori $t5, 0x000a
subu $t6, $t2, $t4
subu $t7, $t3, $t5
sltiu $v0, $t6, 1
sltiu $v1, $t7, 1
and $v0, $v0, $v1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : j.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'j' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
j $target
ori $v0, $0, 0 # The test result starts as a failure
$finish:
sw $v0, 8($s0)
sw $s1, 4($s0)
jr $ra
nop
j $finish # Early-by-1 detection
$target:
nop
ori $v0, $0, 1 # Set the result to pass
j $finish # Late-by 1 detection (result not written)
nop
#### Test code end ####
.end test
###############################################################################
# File : jal.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'jal' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
ori $v1, $ra, 0 # Save $ra
jal $target
ori $v0, $0, 0 # The test result starts as a failure
$finish:
sw $v0, 8($s0)
ori $ra, $v1, 0 # Restore $ra
sw $s1, 4($s0)
jr $ra
nop
j $finish # Early-by-1 detection
$target:
nop
ori $v0, $0, 1 # Set the result to pass
jr $ra
nop
#### Test code end ####
.end test
###############################################################################
# File : jalr.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'jalr' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
ori $v1, $ra, 0 # Save $ra
la $t0, $target
jalr $t0
ori $v0, $0, 0 # The test result starts as a failure
$finish:
sw $v0, 8($s0)
ori $ra, $v1, 0 # Restore $ra
sw $s1, 4($s0)
jr $ra
nop
j $finish # Early-by-1 detection
$target:
nop
ori $v0, $0, 1 # Set the result to pass
jr $ra
nop
#### Test code end ####
.end test
###############################################################################
# File : jr.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'jr' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
la $t0, $target
jr $t0
ori $v0, $0, 0 # The test result starts as a failure
$finish:
sw $v0, 8($s0)
sw $s1, 4($s0)
jr $ra
nop
j $finish # Early-by-1 detection
$target:
nop
ori $v0, $0, 1 # Set the result to pass
j $finish
nop
#### Test code end ####
.end test
###############################################################################
# File : lb.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'lb' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xbfc0 # Load address 0xbfc007fc (last word in 2KB starting
ori $t0, 0x07fc # from 0xbfc00000)
lui $t1, 0xc001
ori $t1, 0x7afe
sw $t1, 0($t0)
lb $t2, 0($t0)
lb $t3, 1($t0)
lb $t4, 2($t0)
lb $t5, 3($t0)
.ifdef big_endian
lui $t6, 0xffff
ori $t6, 0xffc0
lui $t7, 0x0000
ori $t7, 0x0001
lui $t8, 0x0000
ori $t8, 0x007a
lui $t9, 0xffff
ori $t9, 0xfffe
.else
lui $t6, 0xffff
ori $t6, 0xfffe
lui $t7, 0x0000
ori $t7, 0x007a
lui $t8, 0x0000
ori $t8, 0x0001
lui $t9, 0xffff
ori $t9, 0xffc0
.endif
subu $v1, $t2, $t6
sltiu $v0, $v1, 1
subu $v1, $t3, $t7
sltiu $v1, $v1, 1
and $v0, $v0, $v1
subu $v1, $t4, $t8
sltiu $v1, $v1, 1
and $v0, $v0, $v1
subu $v1, $t5, $t9
sltiu $v1, $v1, 1
and $v0, $v0, $v1
# Repeat with halves swapped (sign extension corner cases)
lui $t1, 0x7afe
ori $t1, 0xc001
sw $t1, 0($t0)
lb $t2, 0($t0)
lb $t3, 1($t0)
lb $t4, 2($t0)
lb $t5, 3($t0)
.ifdef big_endian
lui $t6, 0x0000
ori $t6, 0x007a
lui $t7, 0xffff
ori $t7, 0xfffe
lui $t8, 0xffff
ori $t8, 0xffc0
lui $t9, 0x0000
ori $t9, 0x0001
.else
lui $t6, 0x0000
ori $t6, 0x0001
lui $t7, 0xffff
ori $t7, 0xffc0
lui $t8, 0xffff
ori $t8, 0xfffe
lui $t9, 0x0000
ori $t9, 0x007a
.endif
subu $v1, $t2, $t6
sltiu $v1, $v1, 1
and $v0, $v0, $v1
subu $v1, $t3, $t7
sltiu $v1, $v1, 1
and $v0, $v0, $v1
subu $v1, $t4, $t8
sltiu $v1, $v1, 1
and $v0, $v0, $v1
subu $v1, $t5, $t9
sltiu $v1, $v1, 1
and $v0, $v0, $v1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : lbu.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'lbu' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xbfc0 # Load address 0xbfc007fc (last word in 2KB starting
ori $t0, 0x07fc # from 0xbfc00000)
lui $t1, 0xc001
ori $t1, 0x7afe
sw $t1, 0($t0)
lbu $t2, 0($t0)
lbu $t3, 1($t0)
lbu $t4, 2($t0)
lbu $t5, 3($t0)
.ifdef big_endian
ori $t6, $0, 0x00c0
ori $t7, $0, 0x0001
ori $t8, $0, 0x007a
ori $t9, $0, 0x00fe
.else
ori $t6, $0, 0x00fe
ori $t7, $0, 0x007a
ori $t8, $0, 0x0001
ori $t9, $0, 0x00c0
.endif
subu $v1, $t2, $t6
sltiu $v0, $v1, 1
subu $v1, $t3, $t7
sltiu $v1, $v1, 1
and $v0, $v0, $v1
subu $v1, $t4, $t8
sltiu $v1, $v1, 1
and $v0, $v0, $v1
subu $v1, $t5, $t9
sltiu $v1, $v1, 1
and $v0, $v0, $v1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : lh.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'lh' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xbfc0 # Load address 0xbfc007fc (last word in 2KB starting
ori $t0, 0x07fc # from 0xbfc00000)
lui $t1, 0x7001
ori $t1, 0xcafe
sw $t1, 0($t0)
lh $t2, 0($t0)
lh $t3, 2($t0)
.ifdef big_endian
lui $t4, 0x0000
ori $t4, 0x7001
lui $t5, 0xffff
ori $t5, 0xcafe
.else
lui $t4, 0xffff
ori $t4, 0xcafe
lui $t5, 0x0000
ori $t5, 0x7001
.endif
subu $v1, $t2, $t4
sltiu $v0, $v1, 1
subu $v1, $t3, $t5
sltiu $v1, $v1, 1
and $v0, $v0, $v1
# Repeat with halves swapped (sign extension corner cases)
lui $t1, 0xcafe
ori $t1, 0x7001
sw $t1, 0($t0)
lh $t2, 0($t0)
lh $t3, 2($t0)
.ifdef big_endian
lui $t4, 0xffff
ori $t4, 0xcafe
lui $t5, 0x0000
ori $t5, 0x7001
.else
lui $t4, 0x0000
ori $t4, 0x7001
lui $t5, 0xffff
ori $t5, 0xcafe
.endif
subu $v1, $t2, $t4
sltiu $v1, $v1, 1
and $v0, $v0, $v1
subu $v1, $t3, $t5
sltiu $v1, $v1, 1
and $v0, $v0, $v1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : lhu.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'lhu' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xbfc0 # Load address 0xbfc007fc (last word in 2KB starting
ori $t0, 0x07fc # from 0xbfc00000)
lui $t1, 0x7001
ori $t1, 0xcafe
sw $t1, 0($t0)
lhu $t2, 0($t0)
lhu $t3, 2($t0)
.ifdef big_endian
ori $t4, $0, 0x7001
ori $t5, $0, 0xcafe
.else
ori $t4, $0, 0xcafe
ori $t5, $0, 0x7001
.endif
subu $v1, $t2, $t4
sltiu $v0, $v1, 1
subu $v1, $t3, $t5
sltiu $v1, $v1, 1
and $v0, $v0, $v1
# Repeat with halves swapped (sign extension corner cases)
lui $t1, 0xcafe
ori $t1, 0x7001
sw $t1, 0($t0)
lhu $t2, 0($t0)
lhu $t3, 2($t0)
.ifdef big_endian
ori $t4, $0, 0xcafe
ori $t5, $0, 0x7001
.else
ori $t4, $0, 0x7001
ori $t5, $0, 0xcafe
.endif
subu $v1, $t2, $t4
sltiu $v1, $v1, 1
and $v0, $v0, $v1
subu $v1, $t3, $t5
sltiu $v1, $v1, 1
and $v0, $v0, $v1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : lui.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'lui' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
ori $v0, $0, 1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : lw.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'lw' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xbfc0 # Load a valid address (last word in 2KB starting
ori $t0, 0x07fc # from 0xbfc00000)
sw $0, 0($t0)
ori $t1, $0, 1
sw $t1, 0($t0)
lw $v0, 0($t0)
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : lwl.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'lwl' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xbfc0 # Load address 0xbfc007fc (last word in 2KB starting
ori $t0, 0x07fc # from 0xbfc00000)
lui $t1, 0xc001 # Memory word is 0xc001cafe
ori $t1, 0xcafe
sw $t1, 0($t0)
lui $t2, 0xdeaf # Register word is 0xdeafbeef
ori $t2, 0xbeef
or $t3, $0, $t2
or $t4, $0, $t2
or $t5, $0, $t2
or $t6, $0, $t2
lwl $t3, 0($t0)
lwl $t4, 1($t0)
lwl $t5, 2($t0)
lwl $t6, 3($t0)
.ifdef big_endian
lui $s3, 0xc001 # 0xc001cafe
ori $s3, 0xcafe
lui $s4, 0x01ca # 0x01cafeef
ori $s4, 0xfeef
lui $s5, 0xcafe # 0xcafebeef
ori $s5, 0xbeef
lui $s6, 0xfeaf # 0xfeafbeef
ori $s6, 0xbeef
.else
lui $s3, 0xfeaf # 0xfeafbeef
ori $s3, 0xbeef
lui $s4, 0xcafe # 0xcafebeef
ori $s4, 0xbeef
lui $s5, 0x01ca # 0x01cafeef
ori $s5, 0xfeef
lui $s6, 0xc001 # 0xc001cafe
ori $s6, 0xcafe
.endif
subu $s2, $t3, $s3
sltiu $v0, $s2, 1
subu $s2, $t4, $s4
sltiu $v1, $s2, 1
and $v0, $v0, $v1
subu $s2, $t5, $s5
sltiu $v1, $s2, 1
and $v0, $v0, $v1
subu $s2, $t6, $s6
sltiu $v1, $s2, 1
and $v0, $v0, $v1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : lwr.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'lwr' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xbfc0 # Load address 0xbfc007fc (last word in 2KB starting
ori $t0, 0x07fc # from 0xbfc00000)
lui $t1, 0xc001 # Memory word is 0xc001cafe
ori $t1, 0xcafe
sw $t1, 0($t0)
lui $t2, 0xdeaf # Register word is 0xdeafbeef
ori $t2, 0xbeef
or $t3, $0, $t2
or $t4, $0, $t2
or $t5, $0, $t2
or $t6, $0, $t2
lwr $t3, 0($t0)
lwr $t4, 1($t0)
lwr $t5, 2($t0)
lwr $t6, 3($t0)
.ifdef big_endian
lui $s3, 0xdeaf # 0xdeafbec0
ori $s3, 0xbec0
lui $s4, 0xdeaf # 0xdeafc001
ori $s4, 0xc001
lui $s5, 0xdec0 # 0xdec001ca
ori $s5, 0x01ca
lui $s6, 0xc001 # 0xc001cafe
ori $s6, 0xcafe
.else
lui $s3, 0xc001 # 0xc001cafe
ori $s3, 0xcafe
lui $s4, 0xdec0 # 0xdec001ca
ori $s4, 0x01ca
lui $s5, 0xdeaf # 0xdeafc001
ori $s5, 0xc001
lui $s6, 0xdeaf # 0xdeafbec0
ori $s6, 0xbec0
.endif
subu $s2, $t3, $s3
sltiu $v0, $s2, 1
subu $s2, $t4, $s4
sltiu $v1, $s2, 1
and $v0, $v0, $v1
subu $s2, $t5, $s5
sltiu $v1, $s2, 1
and $v0, $v0, $v1
subu $s2, $t6, $s6
sltiu $v1, $s2, 1
and $v0, $v0, $v1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : mfthi.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'mthi' and 'mfhi' instructions.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xdeaf
ori $t0, 0xbeef
mthi $t0
mfhi $t1
subu $v1, $t0, $t1
sltiu $v0, $v1, 1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : mftlo.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'mtlo' and 'mflo' instructions.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xdeaf
ori $t0, 0xbeef
mtlo $t0
mflo $t1
subu $v1, $t0, $t1
sltiu $v0, $v1, 1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : movn.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'movn' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xdeaf
ori $t0, $t0, 0xbeef
ori $t1, $0, 0
movn $t2, $t0, $s1 # $t2 gets 0xdeafbeef
movn $t1, $t0, $0 # $t1 remains 0
subu $t3, $t2, $t0
sltiu $v0, $t3, 1
sltiu $v1, $t1, 1
and $v0, $v0, $v1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : movz.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'movz' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xdeaf
ori $t0, $t0, 0xbeef
ori $t2, $0, 0
movz $t2, $t0, $s0 # $t2 remains 0
movz $t1, $t0, $0 # $t1 gets 0xdeafbeef
subu $t3, $t1, $t0
sltiu $v0, $t3, 1
sltiu $v1, $t2, 1
and $v0, $v0, $v1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : mul.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'mul' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0x1234
ori $t0, 0x5678
lui $t1, 0xc001
ori $t1, 0xcafe
mul $t2, $t0, $t1 # 0xb2a07b10
lui $t3, 0xb2a0
ori $t3, 0x7b10
subu $t4, $t2, $t3
sltiu $v0, $t4, 1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : mult.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'mult' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0x1234
ori $t0, 0x5678
lui $t1, 0xc001
ori $t1, 0xcafe
mult $t0, $t1 # 0xfb730b05b2a07b10
mfhi $t2
mflo $t3
lui $t4, 0xfb73
ori $t4, 0x0b05
lui $t5, 0xb2a0
ori $t5, 0x7b10
subu $t6, $t2, $t4
subu $t7, $t3, $t5
sltiu $v0, $t6, 1
sltiu $v1, $t7, 1
and $v0, $v0, $v1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : multu.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'multu' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0x1234
ori $t0, 0x5678
lui $t1, 0xc001
ori $t1, 0xcafe
multu $t0, $t1 # 0x0da7617db2a07b10
mfhi $t2
mflo $t3
lui $t4, 0x0da7
ori $t4, 0x617d
lui $t5, 0xb2a0
ori $t5, 0x7b10
subu $t6, $t2, $t4
subu $t7, $t3, $t5
sltiu $v0, $t6, 1
sltiu $v1, $t7, 1
and $v0, $v0, $v1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : nor.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'nor' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xdeaf # A = 0xdeafbeef
ori $t0, $t0, 0xbeef
lui $t1, 0x3141 # B = 0x31415926
ori $t1, $t1, 0x5926
lui $t2, 0xffff # C = 0xfffffffe
ori $t2, $t2, 0xfffe
nor $t3, $t0, $t1 # D = nor(A,B) = 0x00100010
nor $v0, $t2, $t3 # E = nor(C,D) = 0x1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
# load hash at 0x30001000
# 0x47173285 a8d7341e 5e972fc6 77286384 f802f8ef 42a5ec5f 03bbfa25 4cb01fad = "hello world"
test:
lui $s0, 0x3000
ori $s0, 0x1000
lui $t0, 0x4717
ori $t0, 0x3285
sw $t0, 0($s0)
lui $t0, 0xa8d7
ori $t0, 0x341e
sw $t0, 4($s0)
lui $t0, 0x5e97
ori $t0, 0x2fc6
sw $t0, 8($s0)
lui $t0, 0x7728
ori $t0, 0x6384
sw $t0, 0xc($s0)
lui $t0, 0xf802
ori $t0, 0xf8ef
sw $t0, 0x10($s0)
lui $t0, 0x42a5
ori $t0, 0xec5f
sw $t0, 0x14($s0)
lui $t0, 0x03bb
ori $t0, 0xfa25
sw $t0, 0x18($s0)
lui $t0, 0x4cb0
ori $t0, 0x1fad
sw $t0, 0x1c($s0)
# syscall 4020 to trigger
li $v0, 4020
syscall
# length at 0x31000000
lui $s1, 0x3100
lw $t0, 0($s1)
# should be len("hello world") == 11
li $t4, 11
subu $t5, $t0, $t4
sltiu $v0, $t5, 1
# data at 0x31000004
lw $t0, 4($s1)
lui $t4, 0x6865
ori $t4, 0x6c6c
subu $t5, $t0, $t4
sltiu $v1, $t5, 1
and $v0, $v0, $v1
# save results
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : ori.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'ori' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
ori $v0, $s1, 0
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : sb.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'sb' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xbfc0 # Load address 0xbfc007fc (last word in 2KB starting
ori $t0, 0x07fc # from 0xbfc00000)
sw $0, 0($t0)
ori $t1, $0, 0xc0
ori $t2, $0, 0x01
ori $t3, $0, 0xca
ori $t4, $0, 0xfe
sb $t1, 0($t0)
sb $t2, 1($t0)
sb $t3, 2($t0)
sb $t4, 3($t0)
lw $t5, 0($t0)
.ifdef big_endian
lui $t6, 0xc001
ori $t6, 0xcafe
.else
lui $t6, 0xfeca
ori $t6, 0x01c0
.endif
subu $t7, $t5, $t6
sltiu $v0, $t7, 1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : sh.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'sh' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xbfc0 # Load address 0xbfc007fc (last word in 2KB starting
ori $t0, 0x07fc # from 0xbfc00000)
sw $0, 0($t0)
ori $t1, $0, 0xc001
ori $t2, $0, 0xcafe
sh $t1, 0($t0)
sh $t2, 2($t0)
lw $t3, 0($t0)
.ifdef big_endian
lui $t4, 0xc001
ori $t4, 0xcafe
.else
lui $t4, 0xcafe
ori $t4, 0xc001
.endif
subu $t5, $t3, $t4
sltiu $v0, $t5, 1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : sll.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'sll' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xdeaf # A = 0xdeafbeef
ori $t0, 0xbeef
sll $t1, $t0, 4 # B = 0xdeafbeef << 4 = 0xeafbeef0
lui $t2, 0xeafb # C = 0xeafbeef0
ori $t2, 0xeef0
subu $t3, $t1, $t2
sltiu $v0, $t3, 1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : sllv.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'sllv' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xdeaf # A = 0xdeafbeef
ori $t0, 0xbeef
ori $t1, $0, 12
sllv $t2, $t0, $t1 # B = 0xdeafbeef << 12 = 0xfbeef000
lui $t3, 0xfbee
ori $t3, 0xf000
subu $t4, $t2, $t3
sltiu $v0, $t4, 1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : slt.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'slt' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xffff
ori $t0, 0xffff
slt $v0, $t0, $s1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : slti.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'slti' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0x8000
slti $v0, $t0, 0xffff
slti $v1, $t0, 0
and $v0, $v0, $v1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : sltiu.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'sltiu' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0x8000
sltiu $v0, $t0, 0xffff
sltiu $v1, $0, 0xffff
and $v0, $v0, $v1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : sltu.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'sltu' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xffff
ori $t0, 0xffff
sltu $v0, $s1, $t0
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : sra.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'sra' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xdeaf # A = 0xdeafbeef
ori $t0, 0xbeef
sra $t1, $t0, 4 # B = 0xdeafbeef >> 4 = 0xfdeafbee
lui $t2, 0xfdea # C = 0xfdeafbee
ori $t2, 0xfbee
subu $t3, $t1, $t2 # D = B - C = 0
sltiu $v0, $t3, 1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : srav.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'srav' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xdeaf # A = 0xdeafbeef
ori $t0, 0xbeef
ori $t1, $0, 12
srav $t2, $t0, $t1 # B = 0xdeafbeef >> 12 = 0xfffdeafb
lui $t3, 0xfffd
ori $t3, 0xeafb
subu $t4, $t2, $t3
sltiu $v0, $t4, 1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : srl.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'srl' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xdeaf # A = 0xdeafbeef
ori $t0, 0xbeef
srl $t1, $t0, 4 # B = 0xdeafbeef >> 4 = 0x0deafbee
lui $t2, 0x0dea
ori $t2, 0xfbee
subu $t3, $t1, $t2 # D = B - C = 0
sltiu $v0, $t3, 1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : srlv.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'srlv' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xdeaf # A = 0xdeafbeef
ori $t0, 0xbeef
ori $t1, $0, 12
srlv $t2, $t0, $t1 # B = 0xdeafbeef >> 12 = 0x000deafb
lui $t3, 0x000d
ori $t3, 0xeafb
subu $t4, $t2, $t3
sltiu $v0, $t4, 1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : sub.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'sub' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xffff # A = 0xfffffffd (-3)
ori $t0, 0xfffd
sub $t1, $t0, $t0 # B = A - A = 0
sub $t2, $t1, $t0 # C = B - A = 0 - A = 3
ori $t3, $0, 3 # D = 2
sub $t4, $t2, $t3 # E = C - D = C - 2 = 0
sltiu $v0, $t4, 1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : subu.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'subu' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xffff # A = 0xfffffffd (-3)
ori $t0, 0xfffd
ori $t1, $0, 4 # B = 4
subu $t2, $t0, $t1 # C = A - B = 0xfffffff9 (-7)
lui $t3, 0xffff # D = 0xfffffff8 (like -8 mod 2^32)
ori $t3, 0xfff8
subu $t4, $t2, $t3 # F = C - D = 1
subu $t5, $t4, $s1 # G = F - 1 = 0
sltiu $v0, $t5, 1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : swl.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'swl' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xbfc0 # Load address 0xbfc007ec (last four words in 2KB starting
ori $t0, 0x07ec # from 0xbfc00000)
lui $t1, 0xc001 # Memory word is 0xc001cafe
ori $t1, 0xcafe
sw $t1, 0($t0)
sw $t1, 4($t0)
sw $t1, 8($t0)
sw $t1, 12($t0)
lui $t2, 0xdeaf # Register word is 0xdeafbeef
ori $t2, 0xbeef
swl $t2, 0($t0)
swl $t2, 5($t0)
swl $t2, 10($t0)
swl $t2, 15($t0)
lw $s2, 0($t0)
lw $s3, 4($t0)
lw $s4, 8($t0)
lw $s5, 12($t0)
.ifdef big_endian
lui $t3, 0xdeaf # 0xdeafbeef
ori $t3, 0xbeef
lui $t4, 0xc0de # 0xc0deafbe
ori $t4, 0xafbe
lui $t5, 0xc001 # 0xc001deaf
ori $t5, 0xdeaf
lui $t6, 0xc001 # 0xc001cade
ori $t6, 0xcade
.else
lui $t3, 0xc001 # 0xc001cade
ori $t3, 0xcade
lui $t4, 0xc001 # 0xc001deaf
ori $t4, 0xdeaf
lui $t5, 0xc0de # 0xc0deafbe
ori $t5, 0xafbe
lui $t6, 0xdeaf # 0xdeafbeef
ori $t6, 0xbeef
.endif
subu $t7, $s2, $t3
sltiu $v0, $t7, 1
subu $t7, $s3, $t4
sltiu $v1, $t7, 1
and $v0, $v0, $v1
subu $t7, $s4, $t5
sltiu $v1, $t7, 1
and $v0, $v0, $v1
subu $t7, $s5, $t6
sltiu $v1, $t7, 1
and $v0, $v0, $v1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : swr.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'swr' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xbfc0 # Load address 0xbfc007ec (last four words in 2KB starting
ori $t0, 0x07ec # from 0xbfc00000)
lui $t1, 0xc001 # Memory words are 0xc001cafe
ori $t1, 0xcafe
sw $t1, 0($t0)
sw $t1, 4($t0)
sw $t1, 8($t0)
sw $t1, 12($t0)
lui $t2, 0xdeaf # Register word is 0xdeafbeef
ori $t2, 0xbeef
swr $t2, 0($t0)
swr $t2, 5($t0)
swr $t2, 10($t0)
swr $t2, 15($t0)
lw $s2, 0($t0)
lw $s3, 4($t0)
lw $s4, 8($t0)
lw $s5, 12($t0)
.ifdef big_endian
lui $t3, 0xef01 # 0xef01cafe
ori $t3, 0xcafe
lui $t4, 0xbeef # 0xbeefcafe
ori $t4, 0xcafe
lui $t5, 0xafbe # 0xafbeeffe
ori $t5, 0xeffe
lui $t6, 0xdeaf # 0xdeafbeef
ori $t6, 0xbeef
.else
lui $t3, 0xdeaf # 0xdeafbeef
ori $t3, 0xbeef
lui $t4, 0xafbe # 0xafbeeffe
ori $t4, 0xeffe
lui $t5, 0xbeef # 0xbeefcafe
ori $t5, 0xcafe
lui $t6, 0xef01 # 0xef01cafe
ori $t6, 0xcafe
.endif
subu $t7, $s2, $t3
sltiu $v0, $t7, 1
subu $t7, $s3, $t4
sltiu $v1, $t7, 1
and $v0, $v0, $v1
subu $t7, $s4, $t5
sltiu $v1, $t7, 1
and $v0, $v0, $v1
subu $t7, $s5, $t6
sltiu $v1, $t7, 1
and $v0, $v0, $v1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : xor.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'xor' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
lui $t0, 0xdeaf # A = 0xdeafbeef
ori $t0, 0xbeef
lui $t1, 0x3141 # B = 0x31415926
ori $t1, 0x5926
lui $t2, 0xefee # C = 0xefeee7c8
ori $t2, 0xe7c8
xor $t3, $t0, $t1 # D = xor(A,B) = 0xefeee7c8
xor $t4, $t2, $t3 # E = xor(C,D) = 0x1
xor $t5, $t4, $s1 # F = xor(E,1) = 0
sltiu $v0, $t5, 1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
###############################################################################
# File : xori.asm
# Project : MIPS32 MUX
# Author: : Grant Ayers (ayers@cs.stanford.edu)
#
# Standards/Formatting:
# MIPS gas, soft tab, 80 column
#
# Description:
# Test the functionality of the 'xori' instruction.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
#### Test code start ####
ori $t0, $0, 0xdeaf # A = 0xdeaf
xori $t1, $t0, 0x3141 # B = xor(A, 0x3141) = 0xefee
xori $t2, $t1, 0xefef # C = xor(B, 0xefef) = 0x1
xori $t3, $t2, 1 # D = xor(C, 1) = 0
sltiu $v0, $t3, 1
#### Test code end ####
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
package mipsevm
import (
"encoding/hex"
"fmt"
"github.com/ethereum/go-ethereum/crypto"
)
type Page [PageSize]byte
func (p *Page) MarshalText() ([]byte, error) {
dst := make([]byte, hex.EncodedLen(len(p)))
hex.Encode(dst, p[:])
return dst, nil
}
func (p *Page) UnmarshalText(dat []byte) error {
if len(dat) != PageSize*2 {
return fmt.Errorf("expected %d hex chars, but got %d", PageSize*2, len(dat))
}
_, err := hex.Decode(p[:], dat)
return err
}
type CachedPage struct {
Data *Page
// intermediate nodes only
Cache [PageSize / 32][32]byte
// true if the intermediate node is valid
Ok [PageSize / 32]bool
}
func (p *CachedPage) Invalidate(pageAddr uint32) {
if pageAddr >= PageSize {
panic("invalid page addr")
}
k := (1 << PageAddrSize) | pageAddr
// first cache layer caches nodes that has two 32 byte leaf nodes.
k >>= 5 + 1
for k > 0 {
p.Ok[k] = false
k >>= 1
}
}
func (p *CachedPage) InvalidateFull() {
p.Ok = [PageSize / 32]bool{} // reset everything to false
}
func (p *CachedPage) MerkleRoot() [32]byte {
// hash the bottom layer
for i := uint64(0); i < PageSize; i += 64 {
j := PageSize/32/2 + i/64
if p.Ok[j] {
continue
}
p.Cache[j] = crypto.Keccak256Hash(p.Data[i : i+64])
//fmt.Printf("0x%x 0x%x -> 0x%x\n", p.Data[i:i+32], p.Data[i+32:i+64], p.Cache[j])
p.Ok[j] = true
}
// hash the cache layers
for i := PageSize/32 - 2; i > 0; i -= 2 {
j := i >> 1
if p.Ok[j] {
continue
}
p.Cache[j] = HashPair(p.Cache[i], p.Cache[i+1])
p.Ok[j] = true
}
return p.Cache[1]
}
func (p *CachedPage) MerkleizeSubtree(gindex uint64) [32]byte {
_ = p.MerkleRoot() // fill cache
if gindex >= PageSize/32 {
if gindex >= PageSize/32*2 {
panic("gindex too deep")
}
// it's pointing to a bottom node
nodeIndex := gindex & (PageAddrMask >> 5)
return *(*[32]byte)(p.Data[nodeIndex*32 : nodeIndex*32+32])
}
return p.Cache[gindex]
}
package mipsevm
import (
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
func TestCachedPage(t *testing.T) {
p := &CachedPage{Data: new(Page)}
p.Data[42] = 0xab
gindex := ((uint64(1) << PageAddrSize) | 42) >> 5
node := common.Hash(p.MerkleizeSubtree(gindex))
expectedLeaf := common.Hash{10: 0xab}
require.Equal(t, expectedLeaf, node, "leaf nodes should not be hashed")
node = p.MerkleizeSubtree(gindex >> 1)
expectedParent := common.Hash(HashPair(zeroHashes[0], expectedLeaf))
require.Equal(t, expectedParent, node, "can get the parent node")
node = p.MerkleizeSubtree(gindex >> 2)
expectedParentParent := common.Hash(HashPair(expectedParent, zeroHashes[1]))
require.Equal(t, expectedParentParent, node, "and the parent of the parent")
pre := p.MerkleRoot()
p.Data[42] = 0xcd
post := p.MerkleRoot()
require.Equal(t, pre, post, "no change expected until cache is invalidated")
p.Invalidate(42)
post2 := p.MerkleRoot()
require.NotEqual(t, post, post2, "change after cache invalidation")
p.Data[2000] = 0xef
p.Invalidate(42)
post3 := p.MerkleRoot()
require.Equal(t, post2, post3, "local invalidation is not global invalidation")
p.Invalidate(2000)
post4 := p.MerkleRoot()
require.NotEqual(t, post3, post4, "can see the change now")
p.Data[1000] = 0xff
p.InvalidateFull()
post5 := p.MerkleRoot()
require.NotEqual(t, post4, post5, "and global invalidation works regardless of changed data")
}
package mipsevm
import (
"bytes"
"debug/elf"
"encoding/binary"
"fmt"
"io"
)
func LoadELF(f *elf.File) (*State, error) {
s := &State{
PC: uint32(f.Entry),
NextPC: uint32(f.Entry + 4),
HI: 0,
LO: 0,
Heap: 0x20000000,
Registers: [32]uint32{},
Memory: NewMemory(),
ExitCode: 0,
Exited: false,
Step: 0,
}
for i, prog := range f.Progs {
if prog.Type == 0x70000003 { // MIPS_ABIFLAGS
continue
}
r := io.Reader(io.NewSectionReader(prog, 0, int64(prog.Filesz)))
if prog.Filesz != prog.Memsz {
if prog.Type == elf.PT_LOAD {
if prog.Filesz < prog.Memsz {
r = io.MultiReader(r, bytes.NewReader(make([]byte, prog.Memsz-prog.Filesz)))
} else {
return nil, fmt.Errorf("invalid PT_LOAD program segment %d, file size (%d) > mem size (%d)", i, prog.Filesz, prog.Memsz)
}
} else {
return nil, fmt.Errorf("program segment %d has different file size (%d) than mem size (%d): filling for non PT_LOAD segments is not supported", i, prog.Filesz, prog.Memsz)
}
}
if prog.Vaddr+prog.Memsz >= uint64(1<<32) {
return nil, fmt.Errorf("program %d out of 32-bit mem range: %x - %x (size: %x)", i, prog.Vaddr, prog.Vaddr+prog.Memsz, prog.Memsz)
}
if err := s.Memory.SetMemoryRange(uint32(prog.Vaddr), r); err != nil {
return nil, fmt.Errorf("failed to read program segment %d: %w", i, err)
}
}
return s, nil
}
func PatchGo(f *elf.File, st *State) error {
symbols, err := f.Symbols()
if err != nil {
return fmt.Errorf("failed to read symbols data, cannot patch program: %w", err)
}
for _, s := range symbols {
// Disable Golang GC by patching the functions that enable the GC to a no-op function.
switch s.Name {
case "runtime.gcenable",
"runtime.init.5", // patch out: init() { go forcegchelper() }
"runtime.main.func1", // patch out: main.func() { newm(sysmon, ....) }
"runtime.deductSweepCredit", // uses floating point nums and interacts with gc we disabled
"runtime.(*gcControllerState).commit",
// these prometheus packages rely on concurrent background things. We cannot run those.
"github.com/prometheus/client_golang/prometheus.init",
"github.com/prometheus/client_golang/prometheus.init.0",
"github.com/prometheus/procfs.init",
"github.com/prometheus/common/model.init",
"github.com/prometheus/client_model/go.init",
"github.com/prometheus/client_model/go.init.0",
"github.com/prometheus/client_model/go.init.1",
// skip flag pkg init, we need to debug arg-processing more to see why this fails
"flag.init",
// We need to patch this out, we don't pass float64nan because we don't support floats
"runtime.check":
// MIPS32 patch: ret (pseudo instruction)
// 03e00008 = jr $ra = ret (pseudo instruction)
// 00000000 = nop (executes with delay-slot, but does nothing)
if err := st.Memory.SetMemoryRange(uint32(s.Value), bytes.NewReader([]byte{
0x03, 0xe0, 0x00, 0x08,
0, 0, 0, 0,
})); err != nil {
return fmt.Errorf("failed to patch Go runtime.gcenable: %w", err)
}
case "runtime.MemProfileRate":
if err := st.Memory.SetMemoryRange(uint32(s.Value), bytes.NewReader(make([]byte, 4))); err != nil { // disable mem profiling, to avoid a lot of unnecessary floating point ops
return err
}
}
}
return nil
}
func PatchStack(st *State) error {
// setup stack pointer
sp := uint32(0x7f_ff_d0_00)
// allocate 1 page for the initial stack data, and 16KB = 4 pages for the stack to grow
if err := st.Memory.SetMemoryRange(sp-4*PageSize, bytes.NewReader(make([]byte, 5*PageSize))); err != nil {
return fmt.Errorf("failed to allocate page for stack content")
}
st.Registers[29] = sp
storeMem := func(addr uint32, v uint32) {
var dat [4]byte
binary.BigEndian.PutUint32(dat[:], v)
_ = st.Memory.SetMemoryRange(addr, bytes.NewReader(dat[:]))
}
// init argc, argv, aux on stack
storeMem(sp+4*1, 0x42) // argc = 0 (argument count)
storeMem(sp+4*2, 0x35) // argv[n] = 0 (terminating argv)
storeMem(sp+4*3, 0) // envp[term] = 0 (no env vars)
storeMem(sp+4*4, 6) // auxv[0] = _AT_PAGESZ = 6 (key)
storeMem(sp+4*5, 4096) // auxv[1] = page size of 4 KiB (value) - (== minPhysPageSize)
storeMem(sp+4*6, 25) // auxv[2] = AT_RANDOM
storeMem(sp+4*7, sp+4*9) // auxv[3] = address of 16 bytes containing random value
storeMem(sp+4*8, 0) // auxv[term] = 0
_ = st.Memory.SetMemoryRange(sp+4*9, bytes.NewReader([]byte("4;byfairdiceroll"))) // 16 bytes of "randomness"
return nil
}
package mipsevm
import (
"encoding/binary"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)
type State struct {
Memory *Memory `json:"memory"`
PreimageKey common.Hash `json:"preimageKey"`
PreimageOffset uint32 `json:"preimageOffset"` // note that the offset includes the 8-byte length prefix
PC uint32 `json:"pc"`
NextPC uint32 `json:"nextPC"`
LO uint32 `json:"lo"`
HI uint32 `json:"hi"`
Heap uint32 `json:"heap"` // to handle mmap growth
ExitCode uint8 `json:"exit"`
Exited bool `json:"exited"`
Step uint64 `json:"step"`
Registers [32]uint32 `json:"registers"`
// LastHint is optional metadata, and not part of the VM state itself.
// It is used to remember the last pre-image hint,
// so a VM can start from any state without fetching prior pre-images,
// and instead just repeat the last hint on setup,
// to make sure pre-image requests can be served.
// The first 4 bytes are a uin32 length prefix.
// Warning: the hint MAY NOT BE COMPLETE. I.e. this is buffered,
// and should only be read when len(LastHint) > 4 && uint32(LastHint[:4]) >= len(LastHint[4:])
LastHint hexutil.Bytes `json:"lastHint,omitempty"`
}
func (s *State) EncodeWitness() []byte {
out := make([]byte, 0)
memRoot := s.Memory.MerkleRoot()
out = append(out, memRoot[:]...)
out = append(out, s.PreimageKey[:]...)
out = binary.BigEndian.AppendUint32(out, s.PreimageOffset)
out = binary.BigEndian.AppendUint32(out, s.PC)
out = binary.BigEndian.AppendUint32(out, s.NextPC)
out = binary.BigEndian.AppendUint32(out, s.LO)
out = binary.BigEndian.AppendUint32(out, s.HI)
out = binary.BigEndian.AppendUint32(out, s.Heap)
out = append(out, s.ExitCode)
if s.Exited {
out = append(out, 1)
} else {
out = append(out, 0)
}
out = binary.BigEndian.AppendUint64(out, s.Step)
for _, r := range s.Registers {
out = binary.BigEndian.AppendUint32(out, r)
}
return out
}
package mipsevm
import (
"bytes"
"debug/elf"
"encoding/binary"
"encoding/hex"
"fmt"
"io"
"os"
"path"
"strings"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require"
preimage "github.com/ethereum-optimism/optimism/op-preimage"
)
// 0xbf_c0_00_00 ... baseAddrEnd is used in tests to write the results to
const baseAddrEnd = 0xbf_ff_ff_f0
// endAddr is used as return-address for tests
const endAddr = 0xa7ef00d0
func TestState(t *testing.T) {
testFiles, err := os.ReadDir("open_mips_tests/test/bin")
require.NoError(t, err)
for _, f := range testFiles {
t.Run(f.Name(), func(t *testing.T) {
if f.Name() == "oracle.bin" {
t.Skip("oracle test needs to be updated to use syscall pre-image oracle")
}
// TODO: currently tests are compiled as flat binary objects
// We can use more standard tooling to compile them to ELF files and get remove maketests.py
fn := path.Join("open_mips_tests/test/bin", f.Name())
//elfProgram, err := elf.Open()
//require.NoError(t, err, "must load test ELF binary")
//state, err := LoadELF(elfProgram)
//require.NoError(t, err, "must load ELF into state")
programMem, err := os.ReadFile(fn)
require.NoError(t, err)
state := &State{PC: 0, NextPC: 4, Memory: NewMemory()}
err = state.Memory.SetMemoryRange(0, bytes.NewReader(programMem))
require.NoError(t, err, "load program into state")
// set the return address ($ra) to jump into when test completes
state.Registers[31] = endAddr
us := NewInstrumentedState(state, nil, os.Stdout, os.Stderr)
for i := 0; i < 1000; i++ {
if us.state.PC == endAddr {
break
}
_, err := us.Step(false)
require.NoError(t, err)
}
require.Equal(t, uint32(endAddr), us.state.PC, "must reach end")
// inspect test result
done, result := state.Memory.GetMemory(baseAddrEnd+4), state.Memory.GetMemory(baseAddrEnd+8)
require.Equal(t, done, uint32(1), "must be done")
require.Equal(t, result, uint32(1), "must have success result")
})
}
}
func TestHello(t *testing.T) {
elfProgram, err := elf.Open("../example/bin/hello.elf")
require.NoError(t, err, "open ELF file")
state, err := LoadELF(elfProgram)
require.NoError(t, err, "load ELF into state")
err = PatchGo(elfProgram, state)
require.NoError(t, err, "apply Go runtime patches")
require.NoError(t, PatchStack(state), "add initial stack")
var stdOutBuf, stdErrBuf bytes.Buffer
us := NewInstrumentedState(state, nil, io.MultiWriter(&stdOutBuf, os.Stdout), io.MultiWriter(&stdErrBuf, os.Stderr))
for i := 0; i < 400_000; i++ {
if us.state.Exited {
break
}
_, err := us.Step(false)
require.NoError(t, err)
}
require.True(t, state.Exited, "must complete program")
require.Equal(t, uint8(0), state.ExitCode, "exit with 0")
require.Equal(t, "hello world!\n", stdOutBuf.String(), "stdout says hello")
require.Equal(t, "", stdErrBuf.String(), "stderr silent")
}
type testOracle struct {
hint func(v []byte)
getPreimage func(k [32]byte) []byte
}
func (t *testOracle) Hint(v []byte) {
t.hint(v)
}
func (t *testOracle) GetPreimage(k [32]byte) []byte {
return t.getPreimage(k)
}
var _ PreimageOracle = (*testOracle)(nil)
func claimTestOracle(t *testing.T) (po PreimageOracle, stdOut string, stdErr string) {
s := uint64(1000)
a := uint64(3)
b := uint64(4)
encodeU64 := func(x uint64) []byte {
return binary.BigEndian.AppendUint64(nil, x)
}
var diff []byte
diff = append(diff, crypto.Keccak256(encodeU64(a))...)
diff = append(diff, crypto.Keccak256(encodeU64(b))...)
preHash := crypto.Keccak256Hash(encodeU64(s))
diffHash := crypto.Keccak256Hash(diff)
images := make(map[[32]byte][]byte)
images[preimage.LocalIndexKey(0).PreimageKey()] = preHash[:]
images[preimage.LocalIndexKey(1).PreimageKey()] = diffHash[:]
images[preimage.LocalIndexKey(2).PreimageKey()] = encodeU64(s*a + b)
oracle := &testOracle{
hint: func(v []byte) {
parts := strings.Split(string(v), " ")
require.Len(t, parts, 2)
p, err := hex.DecodeString(parts[1])
require.NoError(t, err)
require.Len(t, p, 32)
h := common.Hash(*(*[32]byte)(p))
switch parts[0] {
case "fetch-state":
require.Equal(t, h, preHash, "expecting request for pre-state pre-image")
images[preimage.Keccak256Key(preHash).PreimageKey()] = encodeU64(s)
case "fetch-diff":
require.Equal(t, h, diffHash, "expecting request for diff pre-images")
images[preimage.Keccak256Key(diffHash).PreimageKey()] = diff
images[preimage.Keccak256Key(crypto.Keccak256Hash(encodeU64(a))).PreimageKey()] = encodeU64(a)
images[preimage.Keccak256Key(crypto.Keccak256Hash(encodeU64(b))).PreimageKey()] = encodeU64(b)
default:
t.Fatalf("unexpected hint: %q", parts[0])
}
},
getPreimage: func(k [32]byte) []byte {
p, ok := images[k]
if !ok {
t.Fatalf("missing pre-image %s", k)
}
return p
},
}
return oracle, fmt.Sprintf("computing %d * %d + %d\nclaim %d is good!\n", s, a, b, s*a+b), "started!"
}
func TestClaim(t *testing.T) {
elfProgram, err := elf.Open("../example/bin/claim.elf")
require.NoError(t, err, "open ELF file")
state, err := LoadELF(elfProgram)
require.NoError(t, err, "load ELF into state")
err = PatchGo(elfProgram, state)
require.NoError(t, err, "apply Go runtime patches")
require.NoError(t, PatchStack(state), "add initial stack")
oracle, expectedStdOut, expectedStdErr := claimTestOracle(t)
var stdOutBuf, stdErrBuf bytes.Buffer
us := NewInstrumentedState(state, oracle, io.MultiWriter(&stdOutBuf, os.Stdout), io.MultiWriter(&stdErrBuf, os.Stderr))
for i := 0; i < 2000_000; i++ {
if us.state.Exited {
break
}
_, err := us.Step(false)
require.NoError(t, err)
}
require.True(t, state.Exited, "must complete program")
require.Equal(t, uint8(0), state.ExitCode, "exit with 0")
require.Equal(t, expectedStdOut, stdOutBuf.String(), "stdout")
require.Equal(t, expectedStdErr, stdErrBuf.String(), "stderr")
}
package mipsevm
import (
"encoding/binary"
"errors"
"fmt"
preimage "github.com/ethereum-optimism/optimism/op-preimage"
)
type StepWitness struct {
// encoded state witness
State []byte
MemProof []byte
PreimageKey [32]byte // zeroed when no pre-image is accessed
PreimageValue []byte // including the 8-byte length prefix
PreimageOffset uint32
}
func uint32ToBytes32(v uint32) []byte {
var out [32]byte
binary.BigEndian.PutUint32(out[32-4:], v)
return out[:]
}
func (wit *StepWitness) EncodeStepInput() []byte {
var input []byte
input = append(input, StepBytes4...)
input = append(input, uint32ToBytes32(32*2)...) // state data offset in bytes
input = append(input, uint32ToBytes32(32*2+32+uint32(len(wit.State)))...) // proof data offset in bytes
input = append(input, uint32ToBytes32(uint32(len(wit.State)))...) // state data length in bytes
input = append(input, wit.State[:]...)
input = append(input, uint32ToBytes32(uint32(len(wit.MemProof)))...) // proof data length in bytes
input = append(input, wit.MemProof[:]...)
return input
}
func (wit *StepWitness) HasPreimage() bool {
return wit.PreimageKey != ([32]byte{})
}
func (wit *StepWitness) EncodePreimageOracleInput() ([]byte, error) {
if wit.PreimageKey == ([32]byte{}) {
return nil, errors.New("cannot encode pre-image oracle input, witness has no pre-image to proof")
}
switch preimage.KeyType(wit.PreimageKey[0]) {
case preimage.LocalKeyType:
// We have no on-chain form of preparing the bootstrap pre-images onchain yet.
// So instead we cheat them in.
// In production usage there should be an on-chain contract that exposes this,
// rather than going through the global keccak256 oracle.
var input []byte
input = append(input, CheatBytes4...)
input = append(input, uint32ToBytes32(wit.PreimageOffset)...)
input = append(input, wit.PreimageKey[:]...)
var tmp [32]byte
copy(tmp[:], wit.PreimageValue[wit.PreimageOffset:])
input = append(input, tmp[:]...)
input = append(input, uint32ToBytes32(uint32(len(wit.PreimageValue))-8)...)
// Note: we can pad calldata to 32 byte multiple, but don't strictly have to
return input, nil
case preimage.Keccak256KeyType:
var input []byte
input = append(input, LoadKeccak256PreimagePartBytes4...)
input = append(input, uint32ToBytes32(wit.PreimageOffset)...)
input = append(input, uint32ToBytes32(32+32)...) // partOffset, calldata offset
input = append(input, uint32ToBytes32(uint32(len(wit.PreimageValue))-8)...)
input = append(input, wit.PreimageValue[8:]...)
// Note: we can pad calldata to 32 byte multiple, but don't strictly have to
return input, nil
default:
return nil, fmt.Errorf("unsupported pre-image type %d, cannot prepare preimage with key %x offset %d for oracle",
wit.PreimageKey[0], wit.PreimageKey, wit.PreimageOffset)
}
}
...@@ -8,6 +8,7 @@ ignore: ...@@ -8,6 +8,7 @@ ignore:
- "op-bindings/bindings/*.go" - "op-bindings/bindings/*.go"
- "packages/contracts-bedrock/contracts/vendor/WETH9.sol" - "packages/contracts-bedrock/contracts/vendor/WETH9.sol"
- "packages/contracts-bedrock/contracts/echidna" - "packages/contracts-bedrock/contracts/echidna"
- "packages/contracts-bedrock/contracts/cannon" # tested through Go tests
coverage: coverage:
status: status:
patch: patch:
......
...@@ -26,10 +26,12 @@ require ( ...@@ -26,10 +26,12 @@ require (
github.com/multiformats/go-multiaddr v0.8.0 github.com/multiformats/go-multiaddr v0.8.0
github.com/multiformats/go-multiaddr-dns v0.3.1 github.com/multiformats/go-multiaddr-dns v0.3.1
github.com/olekukonko/tablewriter v0.0.5 github.com/olekukonko/tablewriter v0.0.5
github.com/pkg/profile v1.7.0
github.com/prometheus/client_golang v1.14.0 github.com/prometheus/client_golang v1.14.0
github.com/stretchr/testify v1.8.1 github.com/stretchr/testify v1.8.1
github.com/urfave/cli v1.22.9 github.com/urfave/cli v1.22.9
github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa
golang.org/x/crypto v0.6.0
golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb
golang.org/x/sync v0.1.0 golang.org/x/sync v0.1.0
golang.org/x/term v0.6.0 golang.org/x/term v0.6.0
...@@ -62,6 +64,7 @@ require ( ...@@ -62,6 +64,7 @@ require (
github.com/docker/go-units v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect
github.com/edsrzf/mmap-go v1.1.0 // indirect github.com/edsrzf/mmap-go v1.1.0 // indirect
github.com/elastic/gosigar v0.14.2 // indirect github.com/elastic/gosigar v0.14.2 // indirect
github.com/felixge/fgprof v0.9.3 // indirect
github.com/fjl/memsize v0.0.1 // indirect github.com/fjl/memsize v0.0.1 // indirect
github.com/flynn/noise v1.0.0 // indirect github.com/flynn/noise v1.0.0 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect github.com/francoispqt/gojay v1.2.13 // indirect
...@@ -162,7 +165,6 @@ require ( ...@@ -162,7 +165,6 @@ require (
go.uber.org/fx v1.19.1 // indirect go.uber.org/fx v1.19.1 // indirect
go.uber.org/multierr v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect
go.uber.org/zap v1.24.0 // indirect go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.6.0 // indirect
golang.org/x/mod v0.9.0 // indirect golang.org/x/mod v0.9.0 // indirect
golang.org/x/net v0.8.0 // indirect golang.org/x/net v0.8.0 // indirect
golang.org/x/sys v0.6.0 // indirect golang.org/x/sys v0.6.0 // indirect
......
...@@ -146,6 +146,8 @@ github.com/ethereum-optimism/op-geth v1.101106.0-rc.2 h1:F3SGS0XIvRQ0MjL3Rzbx3A6 ...@@ -146,6 +146,8 @@ github.com/ethereum-optimism/op-geth v1.101106.0-rc.2 h1:F3SGS0XIvRQ0MjL3Rzbx3A6
github.com/ethereum-optimism/op-geth v1.101106.0-rc.2/go.mod h1:X9t7oeerFMU9/zMIjZKT/jbIca+O05QqtBTLjL+XVeA= github.com/ethereum-optimism/op-geth v1.101106.0-rc.2/go.mod h1:X9t7oeerFMU9/zMIjZKT/jbIca+O05QqtBTLjL+XVeA=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ= github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ=
github.com/fjl/memsize v0.0.1/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fjl/memsize v0.0.1/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
...@@ -268,6 +270,7 @@ github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo ...@@ -268,6 +270,7 @@ github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE2YxKWtnnQls6rQjjW5oV7qg2U= github.com/google/pprof v0.0.0-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE2YxKWtnnQls6rQjjW5oV7qg2U=
github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg= github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
...@@ -310,6 +313,7 @@ github.com/huin/goupnp v1.1.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFck ...@@ -310,6 +313,7 @@ github.com/huin/goupnp v1.1.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFck
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb-client-go/v2 v2.4.0 h1:HGBfZYStlx3Kqvsv1h2pJixbCl/jhnFtxpKFAv9Tu5k= github.com/influxdata/influxdb-client-go/v2 v2.4.0 h1:HGBfZYStlx3Kqvsv1h2pJixbCl/jhnFtxpKFAv9Tu5k=
...@@ -557,6 +561,8 @@ github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsK ...@@ -557,6 +561,8 @@ github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsK
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=
github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
......
...@@ -33,7 +33,9 @@ bindings: l1block-bindings \ ...@@ -33,7 +33,9 @@ bindings: l1block-bindings \
legacy-erc20-eth-bindings \ legacy-erc20-eth-bindings \
dispute-game-factory-bindings \ dispute-game-factory-bindings \
standard-bridge-bindings \ standard-bridge-bindings \
cross-domain-messenger-bindings cross-domain-messenger-bindings \
cannon-mips \
cannon-preimage-oracle
version: version:
forge --version forge --version
...@@ -134,11 +136,20 @@ standard-bridge-bindings: compile ...@@ -134,11 +136,20 @@ standard-bridge-bindings: compile
cross-domain-messenger-bindings: compile cross-domain-messenger-bindings: compile
./gen_bindings.sh contracts/universal/CrossDomainMessenger.sol:CrossDomainMessenger $(pkg) ./gen_bindings.sh contracts/universal/CrossDomainMessenger.sol:CrossDomainMessenger $(pkg)
cannon-mips: compile
./gen_bindings.sh contracts/cannon/MIPS.sol:MIPS $(pkg)
cannon-preimage-oracle: compile
./gen_bindings.sh contracts/cannon/PreimageOracle.sol:PreimageOracle $(pkg)
more: more:
go run ./gen/main.go \ go run ./gen/main.go \
-artifacts ../packages/contracts-bedrock/artifacts \ -artifacts ../packages/contracts-bedrock/artifacts \
-forge-artifacts ../packages/contracts-bedrock/forge-artifacts \
-out ./bindings \ -out ./bindings \
-contracts SystemConfig,OptimismMintableERC20Factory,L2StandardBridge,L1BlockNumber,LegacyMessagePasser,DeployerWhitelist,Proxy,OptimismPortal,L2ToL1MessagePasser,L2CrossDomainMessenger,SequencerFeeVault,L1Block,LegacyERC20ETH,WETH9,GovernanceToken,L1CrossDomainMessenger,L2ERC721Bridge,OptimismMintableERC721Factory,ProxyAdmin \ -contracts SystemConfig,OptimismMintableERC20Factory,L2StandardBridge,L1BlockNumber,LegacyMessagePasser,DeployerWhitelist,Proxy,OptimismPortal,L2ToL1MessagePasser,L2CrossDomainMessenger,SequencerFeeVault,L1Block,LegacyERC20ETH,WETH9,GovernanceToken,L1CrossDomainMessenger,L2ERC721Bridge,OptimismMintableERC721Factory,ProxyAdmin,MIPS,PreimageOracle \
-source-maps MIPS,PreimageOracle \
-package bindings -package bindings
mkdir: mkdir:
......
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package bindings
import (
"errors"
"math/big"
"strings"
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
)
// Reference imports to suppress errors if they are not otherwise used.
var (
_ = errors.New
_ = big.NewInt
_ = strings.NewReader
_ = ethereum.NotFound
_ = bind.Bind
_ = common.Big1
_ = types.BloomLookup
_ = event.NewSubscription
)
// MIPSMetaData contains all meta data concerning the MIPS contract.
var MIPSMetaData = &bind.MetaData{
ABI: "[{\"inputs\":[],\"name\":\"BRK_START\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"stateData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"proof\",\"type\":\"bytes\"}],\"name\":\"Step\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oracle\",\"outputs\":[{\"internalType\":\"contractIPreimageOracle\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
Bin: "0x608060405234801561001057600080fd5b50611b1c806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063155633fe146100465780637dc0d1d01461006757806398bb138314610098575b600080fd5b61004e61016c565b6040805163ffffffff9092168252519081900360200190f35b61006f610174565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b61015a600480360360408110156100ae57600080fd5b8101906020810181356401000000008111156100c957600080fd5b8201836020820111156100db57600080fd5b803590602001918460018302840111640100000000831117156100fd57600080fd5b91939092909160208101903564010000000081111561011b57600080fd5b82018360208201111561012d57600080fd5b8035906020019184600183028401116401000000008311171561014f57600080fd5b509092509050610190565b60408051918252519081900360200190f35b634000000081565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b600061019a611a62565b608081146101a757600080fd5b604051610600146101b757600080fd5b606486146101c457600080fd5b61016684146101d257600080fd5b6101ef565b8035602084810360031b9190911c8352920192910190565b8560806101fe602082846101d7565b9150915061020e602082846101d7565b9150915061021e600482846101d7565b9150915061022e600482846101d7565b9150915061023e600482846101d7565b9150915061024e600482846101d7565b9150915061025e600482846101d7565b9150915061026e600482846101d7565b9150915061027e600182846101d7565b9150915061028e600182846101d7565b9150915061029e600882846101d7565b6020810190819052909250905060005b60208110156102d0576102c3600483856101d7565b90935091506001016102ae565b505050806101200151156102ee576102e6610710565b915050610708565b6101408101805160010167ffffffffffffffff1690526060810151600090610316908261081e565b9050603f601a82901c16600281148061033557508063ffffffff166003145b15610382576103788163ffffffff1660021461035257601f610355565b60005b60ff16600261036b856303ffffff16601a6108e6565b63ffffffff16901b610959565b9350505050610708565b6101608301516000908190601f601086901c81169190601587901c16602081106103a857fe5b602002015192508063ffffffff851615806103c957508463ffffffff16601c145b156103fa578661016001518263ffffffff16602081106103e557fe5b6020020151925050601f600b86901c166104b1565b60208563ffffffff16101561045d578463ffffffff16600c148061042457508463ffffffff16600d145b8061043557508463ffffffff16600e145b15610446578561ffff169250610458565b6104558661ffff1660106108e6565b92505b6104b1565b60288563ffffffff1610158061047957508463ffffffff166022145b8061048a57508463ffffffff166026145b156104b1578661016001518263ffffffff16602081106104a657fe5b602002015192508190505b60048563ffffffff16101580156104ce575060088563ffffffff16105b806104df57508463ffffffff166001145b156104fe576104f0858784876109c4565b975050505050505050610708565b63ffffffff60006020878316106105635761051e8861ffff1660106108e6565b9095019463fffffffc861661053481600161081e565b915060288863ffffffff161015801561055457508763ffffffff16603014155b1561056157809250600093505b505b600061057189888885610b4d565b63ffffffff9081169150603f8a16908916158015610596575060088163ffffffff1610155b80156105a85750601c8163ffffffff16105b15610687578063ffffffff16600814806105c857508063ffffffff166009145b156105ff576105ed8163ffffffff166008146105e457856105e7565b60005b89610959565b9b505050505050505050505050610708565b8063ffffffff16600a1415610620576105ed858963ffffffff8a1615611213565b8063ffffffff16600b1415610642576105ed858963ffffffff8a161515611213565b8063ffffffff16600c1415610659576105ed6112f8565b60108163ffffffff16101580156106765750601c8163ffffffff16105b15610687576105ed81898988611770565b8863ffffffff1660381480156106a2575063ffffffff861615155b156106d15760018b61016001518763ffffffff16602081106106c057fe5b63ffffffff90921660209290920201525b8363ffffffff1663ffffffff146106ee576106ee84600184611954565b6106fa85836001611213565b9b5050505050505050505050505b949350505050565b6000610728565b602083810382015183520192910190565b60806040518061073a60208285610717565b9150925061074a60208285610717565b9150925061075a60048285610717565b9150925061076a60048285610717565b9150925061077a60048285610717565b9150925061078a60048285610717565b9150925061079a60048285610717565b915092506107aa60048285610717565b915092506107ba60018285610717565b915092506107ca60018285610717565b915092506107da60088285610717565b60209091019350905060005b6020811015610808576107fb60048386610717565b90945091506001016107e6565b506000815281810382a081900390209150505b90565b60008061082a836119f0565b9050600384161561083a57600080fd5b602081019035610857565b60009081526020919091526040902090565b8460051c8160005b601b8110156108af5760208501943583821c60011680156108875760018114610898576108a5565b6108918285610845565b93506108a5565b6108a28483610845565b93505b505060010161085f565b5060805191508181146108ca57630badf00d60005260206000fd5b5050601f8516601c0360031b1c63ffffffff1691505092915050565b600063ffffffff8381167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80850183169190911c821615159160016020869003821681901b830191861691821b92911b0182610943576000610945565b815b90861663ffffffff16179250505092915050565b6000610963611a62565b5060e08051610100805163ffffffff90811690935284831690526080918516156109b357806008018261016001518663ffffffff16602081106109a257fe5b63ffffffff90921660209290920201525b6109bb610710565b95945050505050565b60006109ce611a62565b5060806000600463ffffffff881614806109ee57508663ffffffff166005145b15610a645760008261016001518663ffffffff1660208110610a0c57fe5b602002015190508063ffffffff168563ffffffff16148015610a3457508763ffffffff166004145b80610a5c57508063ffffffff168563ffffffff1614158015610a5c57508763ffffffff166005145b915050610ae1565b8663ffffffff1660061415610a825760008460030b13159050610ae1565b8663ffffffff1660071415610a9f5760008460030b139050610ae1565b8663ffffffff1660011415610ae157601f601087901c1680610ac55760008560030b1291505b8063ffffffff1660011415610adf5760008560030b121591505b505b606082018051608084015163ffffffff169091528115610b27576002610b0c8861ffff1660106108e6565b63ffffffff90811690911b8201600401166080840152610b39565b60808301805160040163ffffffff1690525b610b41610710565b98975050505050505050565b6000603f601a86901c81169086166020821015610f215760088263ffffffff1610158015610b815750600f8263ffffffff16105b15610c28578163ffffffff1660081415610b9d57506020610c23565b8163ffffffff1660091415610bb457506021610c23565b8163ffffffff16600a1415610bcb5750602a610c23565b8163ffffffff16600b1415610be25750602b610c23565b8163ffffffff16600c1415610bf957506024610c23565b8163ffffffff16600d1415610c1057506025610c23565b8163ffffffff16600e1415610c23575060265b600091505b63ffffffff8216610e7157601f600688901c16602063ffffffff83161015610d455760088263ffffffff1610610c6357869350505050610708565b63ffffffff8216610c835763ffffffff86811691161b9250610708915050565b8163ffffffff1660021415610ca75763ffffffff86811691161c9250610708915050565b8163ffffffff1660031415610cd2576103788163ffffffff168763ffffffff16901c826020036108e6565b8163ffffffff1660041415610cf6575050505063ffffffff8216601f84161b610708565b8163ffffffff1660061415610d1a575050505063ffffffff8216601f84161c610708565b8163ffffffff1660071415610d45576103788763ffffffff168763ffffffff16901c886020036108e6565b8163ffffffff1660201480610d6057508163ffffffff166021145b15610d72578587019350505050610708565b8163ffffffff1660221480610d8d57508163ffffffff166023145b15610d9f578587039350505050610708565b8163ffffffff1660241415610dbb578587169350505050610708565b8163ffffffff1660251415610dd7578587179350505050610708565b8163ffffffff1660261415610df3578587189350505050610708565b8163ffffffff1660271415610e0f575050505082821719610708565b8163ffffffff16602a1415610e42578560030b8760030b12610e32576000610e35565b60015b60ff169350505050610708565b8163ffffffff16602b1415610e6b578563ffffffff168763ffffffff1610610e32576000610e35565b50610f1c565b8163ffffffff16600f1415610e945760108563ffffffff16901b92505050610708565b8163ffffffff16601c1415610f1c578063ffffffff1660021415610ebd57505050828202610708565b8063ffffffff1660201480610ed857508063ffffffff166021145b15610f1c578063ffffffff1660201415610ef0579419945b60005b6380000000871615610f12576401fffffffe600197881b169601610ef3565b9250610708915050565b6111ac565b60288263ffffffff16101561108b578163ffffffff1660201415610f6e57610f658660031660080260180363ffffffff168563ffffffff16901c60ff1660086108e6565b92505050610708565b8163ffffffff1660211415610fa457610f658660021660080260100363ffffffff168563ffffffff16901c61ffff1660106108e6565b8163ffffffff1660221415610fd55750505063ffffffff60086003851602811681811b198416918316901b17610708565b8163ffffffff1660231415610fee578392505050610708565b8163ffffffff1660241415611022578560031660080260180363ffffffff168463ffffffff16901c60ff1692505050610708565b8163ffffffff1660251415611057578560021660080260100363ffffffff168463ffffffff16901c61ffff1692505050610708565b8163ffffffff1660261415610f1c5750505063ffffffff60086003851602601803811681811c198416918316901c17610708565b8163ffffffff16602814156110c35750505060ff63ffffffff60086003861602601803811682811b9091188316918416901b17610708565b8163ffffffff16602914156110fc5750505061ffff63ffffffff60086002861602601003811682811b9091188316918416901b17610708565b8163ffffffff16602a141561112d5750505063ffffffff60086003851602811681811c198316918416901c17610708565b8163ffffffff16602b1415611146578492505050610708565b8163ffffffff16602e141561117a5750505063ffffffff60086003851602601803811681811b198316918416901b17610708565b8163ffffffff1660301415611193578392505050610708565b8163ffffffff16603814156111ac578492505050610708565b604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c696420696e737472756374696f6e00000000000000000000000000604482015290519081900360640190fd5b600061121d611a62565b506080602063ffffffff86161061129557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f76616c6964207265676973746572000000000000000000000000000000000000604482015290519081900360640190fd5b63ffffffff8516158015906112a75750825b156112d557838161016001518663ffffffff16602081106112c457fe5b63ffffffff90921660209290920201525b60808101805163ffffffff808216606085015260049091011690526109bb610710565b6000611302611a62565b506101e051604081015160808083015160a084015160c09094015191936000928392919063ffffffff8616610ffa141561137a5781610fff81161561134c57610fff811661100003015b63ffffffff84166113705760e08801805163ffffffff838201169091529550611374565b8395505b50611723565b8563ffffffff16610fcd14156113965763400000009450611723565b8563ffffffff1661101814156113af5760019450611723565b8563ffffffff1661109614156113e757600161012088015260ff83166101008801526113d9610710565b97505050505050505061081b565b8563ffffffff16610fa314156115a15763ffffffff83166114075761159c565b63ffffffff8316600514156115795760006114298363fffffffc16600161081e565b6000805460208b01516040808d015181517fe03110e1000000000000000000000000000000000000000000000000000000008152600481019390935263ffffffff16602483015280519495509293849373ffffffffffffffffffffffffffffffffffffffff9093169263e03110e19260448082019391829003018186803b1580156114b357600080fd5b505afa1580156114c7573d6000803e3d6000fd5b505050506040513d60408110156114dd57600080fd5b508051602090910151909250905060038516600481900382811015611500578092505b508185101561150d578491505b8260088302610100031c925082600882021b9250600180600883600403021b036001806008858560040301021b0391508119811690508381198616179450505061155f8563fffffffc16600185611954565b60408a018051820163ffffffff169052965061159c915050565b63ffffffff8316600314156115905780945061159c565b63ffffffff9450600993505b611723565b8563ffffffff16610fa414156116755763ffffffff8316600114806115cc575063ffffffff83166002145b806115dd575063ffffffff83166004145b156115ea5780945061159c565b63ffffffff83166006141561159057600061160c8363fffffffc16600161081e565b60208901519091506003841660040383811015611627578093505b83900360089081029290921c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600193850293841b0116911b1760208801526000604088015293508361159c565b8563ffffffff16610fd71415611723578163ffffffff16600314156117175763ffffffff831615806116ad575063ffffffff83166005145b806116be575063ffffffff83166003145b156116cc576000945061159c565b63ffffffff8316600114806116e7575063ffffffff83166002145b806116f8575063ffffffff83166006145b80611709575063ffffffff83166004145b15611590576001945061159c565b63ffffffff9450601693505b6101608701805163ffffffff808816604090920191909152905185821660e09091015260808801805180831660608b01526004019091169052611764610710565b97505050505050505090565b600061177a611a62565b5060806000601063ffffffff88161415611799575060c08101516118f1565b8663ffffffff16601114156117b95763ffffffff861660c08301526118f1565b8663ffffffff16601214156117d3575060a08101516118f1565b8663ffffffff16601314156117f35763ffffffff861660a08301526118f1565b8663ffffffff16601814156118285763ffffffff600387810b9087900b02602081901c821660c08501521660a08301526118f1565b8663ffffffff166019141561185a5763ffffffff86811681871602602081901c821660c08501521660a08301526118f1565b8663ffffffff16601a14156118a5578460030b8660030b8161187857fe5b0763ffffffff1660c0830152600385810b9087900b8161189457fe5b0563ffffffff1660a08301526118f1565b8663ffffffff16601b14156118f1578463ffffffff168663ffffffff16816118c957fe5b0663ffffffff90811660c0840152858116908716816118e457fe5b0463ffffffff1660a08301525b63ffffffff84161561192657808261016001518563ffffffff166020811061191557fe5b63ffffffff90921660209290920201525b60808201805163ffffffff80821660608601526004909101169052611949610710565b979650505050505050565b600061195f836119f0565b9050600384161561196f57600080fd5b6020810190601f8516601c0360031b83811b913563ffffffff90911b1916178460051c60005b601b8110156119e55760208401933582821c60011680156119bd57600181146119ce576119db565b6119c78286610845565b94506119db565b6119d88583610845565b94505b5050600101611995565b505060805250505050565b60ff81166103800261016681019036906104e601811015611a5c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611aed6023913960400191505060405180910390fd5b50919050565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091526101608101611ac8611acd565b905290565b604051806104000160405280602090602082028036833750919291505056fe636865636b207468617420746865726520697320656e6f7567682063616c6c64617461a164736f6c6343000706000a",
}
// MIPSABI is the input ABI used to generate the binding from.
// Deprecated: Use MIPSMetaData.ABI instead.
var MIPSABI = MIPSMetaData.ABI
// MIPSBin is the compiled bytecode used for deploying new contracts.
// Deprecated: Use MIPSMetaData.Bin instead.
var MIPSBin = MIPSMetaData.Bin
// DeployMIPS deploys a new Ethereum contract, binding an instance of MIPS to it.
func DeployMIPS(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *MIPS, error) {
parsed, err := MIPSMetaData.GetAbi()
if err != nil {
return common.Address{}, nil, nil, err
}
if parsed == nil {
return common.Address{}, nil, nil, errors.New("GetABI returned nil")
}
address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(MIPSBin), backend)
if err != nil {
return common.Address{}, nil, nil, err
}
return address, tx, &MIPS{MIPSCaller: MIPSCaller{contract: contract}, MIPSTransactor: MIPSTransactor{contract: contract}, MIPSFilterer: MIPSFilterer{contract: contract}}, nil
}
// MIPS is an auto generated Go binding around an Ethereum contract.
type MIPS struct {
MIPSCaller // Read-only binding to the contract
MIPSTransactor // Write-only binding to the contract
MIPSFilterer // Log filterer for contract events
}
// MIPSCaller is an auto generated read-only Go binding around an Ethereum contract.
type MIPSCaller struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// MIPSTransactor is an auto generated write-only Go binding around an Ethereum contract.
type MIPSTransactor struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// MIPSFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
type MIPSFilterer struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// MIPSSession is an auto generated Go binding around an Ethereum contract,
// with pre-set call and transact options.
type MIPSSession struct {
Contract *MIPS // Generic contract binding to set the session for
CallOpts bind.CallOpts // Call options to use throughout this session
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
// MIPSCallerSession is an auto generated read-only Go binding around an Ethereum contract,
// with pre-set call options.
type MIPSCallerSession struct {
Contract *MIPSCaller // Generic contract caller binding to set the session for
CallOpts bind.CallOpts // Call options to use throughout this session
}
// MIPSTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
// with pre-set transact options.
type MIPSTransactorSession struct {
Contract *MIPSTransactor // Generic contract transactor binding to set the session for
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
// MIPSRaw is an auto generated low-level Go binding around an Ethereum contract.
type MIPSRaw struct {
Contract *MIPS // Generic contract binding to access the raw methods on
}
// MIPSCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
type MIPSCallerRaw struct {
Contract *MIPSCaller // Generic read-only contract binding to access the raw methods on
}
// MIPSTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
type MIPSTransactorRaw struct {
Contract *MIPSTransactor // Generic write-only contract binding to access the raw methods on
}
// NewMIPS creates a new instance of MIPS, bound to a specific deployed contract.
func NewMIPS(address common.Address, backend bind.ContractBackend) (*MIPS, error) {
contract, err := bindMIPS(address, backend, backend, backend)
if err != nil {
return nil, err
}
return &MIPS{MIPSCaller: MIPSCaller{contract: contract}, MIPSTransactor: MIPSTransactor{contract: contract}, MIPSFilterer: MIPSFilterer{contract: contract}}, nil
}
// NewMIPSCaller creates a new read-only instance of MIPS, bound to a specific deployed contract.
func NewMIPSCaller(address common.Address, caller bind.ContractCaller) (*MIPSCaller, error) {
contract, err := bindMIPS(address, caller, nil, nil)
if err != nil {
return nil, err
}
return &MIPSCaller{contract: contract}, nil
}
// NewMIPSTransactor creates a new write-only instance of MIPS, bound to a specific deployed contract.
func NewMIPSTransactor(address common.Address, transactor bind.ContractTransactor) (*MIPSTransactor, error) {
contract, err := bindMIPS(address, nil, transactor, nil)
if err != nil {
return nil, err
}
return &MIPSTransactor{contract: contract}, nil
}
// NewMIPSFilterer creates a new log filterer instance of MIPS, bound to a specific deployed contract.
func NewMIPSFilterer(address common.Address, filterer bind.ContractFilterer) (*MIPSFilterer, error) {
contract, err := bindMIPS(address, nil, nil, filterer)
if err != nil {
return nil, err
}
return &MIPSFilterer{contract: contract}, nil
}
// bindMIPS binds a generic wrapper to an already deployed contract.
func bindMIPS(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
parsed, err := abi.JSON(strings.NewReader(MIPSABI))
if err != nil {
return nil, err
}
return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil
}
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_MIPS *MIPSRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
return _MIPS.Contract.MIPSCaller.contract.Call(opts, result, method, params...)
}
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_MIPS *MIPSRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
return _MIPS.Contract.MIPSTransactor.contract.Transfer(opts)
}
// Transact invokes the (paid) contract method with params as input values.
func (_MIPS *MIPSRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
return _MIPS.Contract.MIPSTransactor.contract.Transact(opts, method, params...)
}
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_MIPS *MIPSCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
return _MIPS.Contract.contract.Call(opts, result, method, params...)
}
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_MIPS *MIPSTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
return _MIPS.Contract.contract.Transfer(opts)
}
// Transact invokes the (paid) contract method with params as input values.
func (_MIPS *MIPSTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
return _MIPS.Contract.contract.Transact(opts, method, params...)
}
// BRKSTART is a free data retrieval call binding the contract method 0x155633fe.
//
// Solidity: function BRK_START() view returns(uint32)
func (_MIPS *MIPSCaller) BRKSTART(opts *bind.CallOpts) (uint32, error) {
var out []interface{}
err := _MIPS.contract.Call(opts, &out, "BRK_START")
if err != nil {
return *new(uint32), err
}
out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32)
return out0, err
}
// BRKSTART is a free data retrieval call binding the contract method 0x155633fe.
//
// Solidity: function BRK_START() view returns(uint32)
func (_MIPS *MIPSSession) BRKSTART() (uint32, error) {
return _MIPS.Contract.BRKSTART(&_MIPS.CallOpts)
}
// BRKSTART is a free data retrieval call binding the contract method 0x155633fe.
//
// Solidity: function BRK_START() view returns(uint32)
func (_MIPS *MIPSCallerSession) BRKSTART() (uint32, error) {
return _MIPS.Contract.BRKSTART(&_MIPS.CallOpts)
}
// Oracle is a free data retrieval call binding the contract method 0x7dc0d1d0.
//
// Solidity: function oracle() view returns(address)
func (_MIPS *MIPSCaller) Oracle(opts *bind.CallOpts) (common.Address, error) {
var out []interface{}
err := _MIPS.contract.Call(opts, &out, "oracle")
if err != nil {
return *new(common.Address), err
}
out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
return out0, err
}
// Oracle is a free data retrieval call binding the contract method 0x7dc0d1d0.
//
// Solidity: function oracle() view returns(address)
func (_MIPS *MIPSSession) Oracle() (common.Address, error) {
return _MIPS.Contract.Oracle(&_MIPS.CallOpts)
}
// Oracle is a free data retrieval call binding the contract method 0x7dc0d1d0.
//
// Solidity: function oracle() view returns(address)
func (_MIPS *MIPSCallerSession) Oracle() (common.Address, error) {
return _MIPS.Contract.Oracle(&_MIPS.CallOpts)
}
// Step is a paid mutator transaction binding the contract method 0x98bb1383.
//
// Solidity: function Step(bytes stateData, bytes proof) returns(bytes32)
func (_MIPS *MIPSTransactor) Step(opts *bind.TransactOpts, stateData []byte, proof []byte) (*types.Transaction, error) {
return _MIPS.contract.Transact(opts, "Step", stateData, proof)
}
// Step is a paid mutator transaction binding the contract method 0x98bb1383.
//
// Solidity: function Step(bytes stateData, bytes proof) returns(bytes32)
func (_MIPS *MIPSSession) Step(stateData []byte, proof []byte) (*types.Transaction, error) {
return _MIPS.Contract.Step(&_MIPS.TransactOpts, stateData, proof)
}
// Step is a paid mutator transaction binding the contract method 0x98bb1383.
//
// Solidity: function Step(bytes stateData, bytes proof) returns(bytes32)
func (_MIPS *MIPSTransactorSession) Step(stateData []byte, proof []byte) (*types.Transaction, error) {
return _MIPS.Contract.Step(&_MIPS.TransactOpts, stateData, proof)
}
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package bindings
import (
"encoding/json"
"github.com/ethereum-optimism/optimism/op-bindings/solc"
)
const MIPSStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"contracts/cannon/MIPS.sol:MIPS\",\"label\":\"oracle\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_contract(IPreimageOracle)1001\"}],\"types\":{\"t_contract(IPreimageOracle)1001\":{\"encoding\":\"inplace\",\"label\":\"contract IPreimageOracle\",\"numberOfBytes\":\"20\"}}}"
var MIPSStorageLayout = new(solc.StorageLayout)
var MIPSDeployedBin = "0x608060405234801561001057600080fd5b50600436106100415760003560e01c8063155633fe146100465780637dc0d1d01461006757806398bb138314610098575b600080fd5b61004e61016c565b6040805163ffffffff9092168252519081900360200190f35b61006f610174565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b61015a600480360360408110156100ae57600080fd5b8101906020810181356401000000008111156100c957600080fd5b8201836020820111156100db57600080fd5b803590602001918460018302840111640100000000831117156100fd57600080fd5b91939092909160208101903564010000000081111561011b57600080fd5b82018360208201111561012d57600080fd5b8035906020019184600183028401116401000000008311171561014f57600080fd5b509092509050610190565b60408051918252519081900360200190f35b634000000081565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b600061019a611a62565b608081146101a757600080fd5b604051610600146101b757600080fd5b606486146101c457600080fd5b61016684146101d257600080fd5b6101ef565b8035602084810360031b9190911c8352920192910190565b8560806101fe602082846101d7565b9150915061020e602082846101d7565b9150915061021e600482846101d7565b9150915061022e600482846101d7565b9150915061023e600482846101d7565b9150915061024e600482846101d7565b9150915061025e600482846101d7565b9150915061026e600482846101d7565b9150915061027e600182846101d7565b9150915061028e600182846101d7565b9150915061029e600882846101d7565b6020810190819052909250905060005b60208110156102d0576102c3600483856101d7565b90935091506001016102ae565b505050806101200151156102ee576102e6610710565b915050610708565b6101408101805160010167ffffffffffffffff1690526060810151600090610316908261081e565b9050603f601a82901c16600281148061033557508063ffffffff166003145b15610382576103788163ffffffff1660021461035257601f610355565b60005b60ff16600261036b856303ffffff16601a6108e6565b63ffffffff16901b610959565b9350505050610708565b6101608301516000908190601f601086901c81169190601587901c16602081106103a857fe5b602002015192508063ffffffff851615806103c957508463ffffffff16601c145b156103fa578661016001518263ffffffff16602081106103e557fe5b6020020151925050601f600b86901c166104b1565b60208563ffffffff16101561045d578463ffffffff16600c148061042457508463ffffffff16600d145b8061043557508463ffffffff16600e145b15610446578561ffff169250610458565b6104558661ffff1660106108e6565b92505b6104b1565b60288563ffffffff1610158061047957508463ffffffff166022145b8061048a57508463ffffffff166026145b156104b1578661016001518263ffffffff16602081106104a657fe5b602002015192508190505b60048563ffffffff16101580156104ce575060088563ffffffff16105b806104df57508463ffffffff166001145b156104fe576104f0858784876109c4565b975050505050505050610708565b63ffffffff60006020878316106105635761051e8861ffff1660106108e6565b9095019463fffffffc861661053481600161081e565b915060288863ffffffff161015801561055457508763ffffffff16603014155b1561056157809250600093505b505b600061057189888885610b4d565b63ffffffff9081169150603f8a16908916158015610596575060088163ffffffff1610155b80156105a85750601c8163ffffffff16105b15610687578063ffffffff16600814806105c857508063ffffffff166009145b156105ff576105ed8163ffffffff166008146105e457856105e7565b60005b89610959565b9b505050505050505050505050610708565b8063ffffffff16600a1415610620576105ed858963ffffffff8a1615611213565b8063ffffffff16600b1415610642576105ed858963ffffffff8a161515611213565b8063ffffffff16600c1415610659576105ed6112f8565b60108163ffffffff16101580156106765750601c8163ffffffff16105b15610687576105ed81898988611770565b8863ffffffff1660381480156106a2575063ffffffff861615155b156106d15760018b61016001518763ffffffff16602081106106c057fe5b63ffffffff90921660209290920201525b8363ffffffff1663ffffffff146106ee576106ee84600184611954565b6106fa85836001611213565b9b5050505050505050505050505b949350505050565b6000610728565b602083810382015183520192910190565b60806040518061073a60208285610717565b9150925061074a60208285610717565b9150925061075a60048285610717565b9150925061076a60048285610717565b9150925061077a60048285610717565b9150925061078a60048285610717565b9150925061079a60048285610717565b915092506107aa60048285610717565b915092506107ba60018285610717565b915092506107ca60018285610717565b915092506107da60088285610717565b60209091019350905060005b6020811015610808576107fb60048386610717565b90945091506001016107e6565b506000815281810382a081900390209150505b90565b60008061082a836119f0565b9050600384161561083a57600080fd5b602081019035610857565b60009081526020919091526040902090565b8460051c8160005b601b8110156108af5760208501943583821c60011680156108875760018114610898576108a5565b6108918285610845565b93506108a5565b6108a28483610845565b93505b505060010161085f565b5060805191508181146108ca57630badf00d60005260206000fd5b5050601f8516601c0360031b1c63ffffffff1691505092915050565b600063ffffffff8381167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80850183169190911c821615159160016020869003821681901b830191861691821b92911b0182610943576000610945565b815b90861663ffffffff16179250505092915050565b6000610963611a62565b5060e08051610100805163ffffffff90811690935284831690526080918516156109b357806008018261016001518663ffffffff16602081106109a257fe5b63ffffffff90921660209290920201525b6109bb610710565b95945050505050565b60006109ce611a62565b5060806000600463ffffffff881614806109ee57508663ffffffff166005145b15610a645760008261016001518663ffffffff1660208110610a0c57fe5b602002015190508063ffffffff168563ffffffff16148015610a3457508763ffffffff166004145b80610a5c57508063ffffffff168563ffffffff1614158015610a5c57508763ffffffff166005145b915050610ae1565b8663ffffffff1660061415610a825760008460030b13159050610ae1565b8663ffffffff1660071415610a9f5760008460030b139050610ae1565b8663ffffffff1660011415610ae157601f601087901c1680610ac55760008560030b1291505b8063ffffffff1660011415610adf5760008560030b121591505b505b606082018051608084015163ffffffff169091528115610b27576002610b0c8861ffff1660106108e6565b63ffffffff90811690911b8201600401166080840152610b39565b60808301805160040163ffffffff1690525b610b41610710565b98975050505050505050565b6000603f601a86901c81169086166020821015610f215760088263ffffffff1610158015610b815750600f8263ffffffff16105b15610c28578163ffffffff1660081415610b9d57506020610c23565b8163ffffffff1660091415610bb457506021610c23565b8163ffffffff16600a1415610bcb5750602a610c23565b8163ffffffff16600b1415610be25750602b610c23565b8163ffffffff16600c1415610bf957506024610c23565b8163ffffffff16600d1415610c1057506025610c23565b8163ffffffff16600e1415610c23575060265b600091505b63ffffffff8216610e7157601f600688901c16602063ffffffff83161015610d455760088263ffffffff1610610c6357869350505050610708565b63ffffffff8216610c835763ffffffff86811691161b9250610708915050565b8163ffffffff1660021415610ca75763ffffffff86811691161c9250610708915050565b8163ffffffff1660031415610cd2576103788163ffffffff168763ffffffff16901c826020036108e6565b8163ffffffff1660041415610cf6575050505063ffffffff8216601f84161b610708565b8163ffffffff1660061415610d1a575050505063ffffffff8216601f84161c610708565b8163ffffffff1660071415610d45576103788763ffffffff168763ffffffff16901c886020036108e6565b8163ffffffff1660201480610d6057508163ffffffff166021145b15610d72578587019350505050610708565b8163ffffffff1660221480610d8d57508163ffffffff166023145b15610d9f578587039350505050610708565b8163ffffffff1660241415610dbb578587169350505050610708565b8163ffffffff1660251415610dd7578587179350505050610708565b8163ffffffff1660261415610df3578587189350505050610708565b8163ffffffff1660271415610e0f575050505082821719610708565b8163ffffffff16602a1415610e42578560030b8760030b12610e32576000610e35565b60015b60ff169350505050610708565b8163ffffffff16602b1415610e6b578563ffffffff168763ffffffff1610610e32576000610e35565b50610f1c565b8163ffffffff16600f1415610e945760108563ffffffff16901b92505050610708565b8163ffffffff16601c1415610f1c578063ffffffff1660021415610ebd57505050828202610708565b8063ffffffff1660201480610ed857508063ffffffff166021145b15610f1c578063ffffffff1660201415610ef0579419945b60005b6380000000871615610f12576401fffffffe600197881b169601610ef3565b9250610708915050565b6111ac565b60288263ffffffff16101561108b578163ffffffff1660201415610f6e57610f658660031660080260180363ffffffff168563ffffffff16901c60ff1660086108e6565b92505050610708565b8163ffffffff1660211415610fa457610f658660021660080260100363ffffffff168563ffffffff16901c61ffff1660106108e6565b8163ffffffff1660221415610fd55750505063ffffffff60086003851602811681811b198416918316901b17610708565b8163ffffffff1660231415610fee578392505050610708565b8163ffffffff1660241415611022578560031660080260180363ffffffff168463ffffffff16901c60ff1692505050610708565b8163ffffffff1660251415611057578560021660080260100363ffffffff168463ffffffff16901c61ffff1692505050610708565b8163ffffffff1660261415610f1c5750505063ffffffff60086003851602601803811681811c198416918316901c17610708565b8163ffffffff16602814156110c35750505060ff63ffffffff60086003861602601803811682811b9091188316918416901b17610708565b8163ffffffff16602914156110fc5750505061ffff63ffffffff60086002861602601003811682811b9091188316918416901b17610708565b8163ffffffff16602a141561112d5750505063ffffffff60086003851602811681811c198316918416901c17610708565b8163ffffffff16602b1415611146578492505050610708565b8163ffffffff16602e141561117a5750505063ffffffff60086003851602601803811681811b198316918416901b17610708565b8163ffffffff1660301415611193578392505050610708565b8163ffffffff16603814156111ac578492505050610708565b604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c696420696e737472756374696f6e00000000000000000000000000604482015290519081900360640190fd5b600061121d611a62565b506080602063ffffffff86161061129557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f76616c6964207265676973746572000000000000000000000000000000000000604482015290519081900360640190fd5b63ffffffff8516158015906112a75750825b156112d557838161016001518663ffffffff16602081106112c457fe5b63ffffffff90921660209290920201525b60808101805163ffffffff808216606085015260049091011690526109bb610710565b6000611302611a62565b506101e051604081015160808083015160a084015160c09094015191936000928392919063ffffffff8616610ffa141561137a5781610fff81161561134c57610fff811661100003015b63ffffffff84166113705760e08801805163ffffffff838201169091529550611374565b8395505b50611723565b8563ffffffff16610fcd14156113965763400000009450611723565b8563ffffffff1661101814156113af5760019450611723565b8563ffffffff1661109614156113e757600161012088015260ff83166101008801526113d9610710565b97505050505050505061081b565b8563ffffffff16610fa314156115a15763ffffffff83166114075761159c565b63ffffffff8316600514156115795760006114298363fffffffc16600161081e565b6000805460208b01516040808d015181517fe03110e1000000000000000000000000000000000000000000000000000000008152600481019390935263ffffffff16602483015280519495509293849373ffffffffffffffffffffffffffffffffffffffff9093169263e03110e19260448082019391829003018186803b1580156114b357600080fd5b505afa1580156114c7573d6000803e3d6000fd5b505050506040513d60408110156114dd57600080fd5b508051602090910151909250905060038516600481900382811015611500578092505b508185101561150d578491505b8260088302610100031c925082600882021b9250600180600883600403021b036001806008858560040301021b0391508119811690508381198616179450505061155f8563fffffffc16600185611954565b60408a018051820163ffffffff169052965061159c915050565b63ffffffff8316600314156115905780945061159c565b63ffffffff9450600993505b611723565b8563ffffffff16610fa414156116755763ffffffff8316600114806115cc575063ffffffff83166002145b806115dd575063ffffffff83166004145b156115ea5780945061159c565b63ffffffff83166006141561159057600061160c8363fffffffc16600161081e565b60208901519091506003841660040383811015611627578093505b83900360089081029290921c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600193850293841b0116911b1760208801526000604088015293508361159c565b8563ffffffff16610fd71415611723578163ffffffff16600314156117175763ffffffff831615806116ad575063ffffffff83166005145b806116be575063ffffffff83166003145b156116cc576000945061159c565b63ffffffff8316600114806116e7575063ffffffff83166002145b806116f8575063ffffffff83166006145b80611709575063ffffffff83166004145b15611590576001945061159c565b63ffffffff9450601693505b6101608701805163ffffffff808816604090920191909152905185821660e09091015260808801805180831660608b01526004019091169052611764610710565b97505050505050505090565b600061177a611a62565b5060806000601063ffffffff88161415611799575060c08101516118f1565b8663ffffffff16601114156117b95763ffffffff861660c08301526118f1565b8663ffffffff16601214156117d3575060a08101516118f1565b8663ffffffff16601314156117f35763ffffffff861660a08301526118f1565b8663ffffffff16601814156118285763ffffffff600387810b9087900b02602081901c821660c08501521660a08301526118f1565b8663ffffffff166019141561185a5763ffffffff86811681871602602081901c821660c08501521660a08301526118f1565b8663ffffffff16601a14156118a5578460030b8660030b8161187857fe5b0763ffffffff1660c0830152600385810b9087900b8161189457fe5b0563ffffffff1660a08301526118f1565b8663ffffffff16601b14156118f1578463ffffffff168663ffffffff16816118c957fe5b0663ffffffff90811660c0840152858116908716816118e457fe5b0463ffffffff1660a08301525b63ffffffff84161561192657808261016001518563ffffffff166020811061191557fe5b63ffffffff90921660209290920201525b60808201805163ffffffff80821660608601526004909101169052611949610710565b979650505050505050565b600061195f836119f0565b9050600384161561196f57600080fd5b6020810190601f8516601c0360031b83811b913563ffffffff90911b1916178460051c60005b601b8110156119e55760208401933582821c60011680156119bd57600181146119ce576119db565b6119c78286610845565b94506119db565b6119d88583610845565b94505b5050600101611995565b505060805250505050565b60ff81166103800261016681019036906104e601811015611a5c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611aed6023913960400191505060405180910390fd5b50919050565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091526101608101611ac8611acd565b905290565b604051806104000160405280602090602082028036833750919291505056fe636865636b207468617420746865726520697320656e6f7567682063616c6c64617461a164736f6c6343000706000a"
var MIPSDeployedSourceMap = "1025:22394:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1423:45;;;:::i;:::-;;;;;;;;;;;;;;;;;;;1791:29;;;:::i;:::-;;;;;;;;;;;;;;;;;;;14355:4789;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;14355:4789:0;;-1:-1:-1;14355:4789:0;-1:-1:-1;14355:4789:0;:::i;:::-;;;;;;;;;;;;;;;;1423:45;1458:10;1423:45;:::o;1791:29::-;;;;;;:::o;14355:4789::-;14433:7;14448:18;;:::i;:::-;14548:4;14541:5;14538:15;14528:2;;14609:1;14607;14600:11;14528:2;14645:4;14639:11;14652;14636:28;14626:2;;14710:1;14708;14701:11;14626:2;14758:3;14740:16;14737:25;14727:2;;14824:1;14822;14815:11;14727:2;14868:3;14854:12;14851:21;14841:2;;14933:1;14931;14924:11;14841:2;14950:370;;;15168:24;;15156:2;15152:13;;;15149:1;15145:21;15141:52;;;;15202:20;;15248:21;;;15294:18;;;15028:292::o;:::-;15336:16;15387:4;15420:18;15435:2;15432:1;15429;15420:18;:::i;:::-;15412:26;;;;15464:18;15479:2;15476:1;15473;15464:18;:::i;:::-;15456:26;;;;15512:17;15527:1;15524;15521;15512:17;:::i;:::-;15504:25;;;;15562:17;15577:1;15574;15571;15562:17;:::i;:::-;15554:25;;;;15600:17;15615:1;15612;15609;15600:17;:::i;:::-;15592:25;;;;15642:17;15657:1;15654;15651;15642:17;:::i;:::-;15634:25;;;;15680:17;15695:1;15692;15689;15680:17;:::i;:::-;15672:25;;;;15718:17;15733:1;15730;15727;15718:17;:::i;:::-;15710:25;;;;15758:17;15773:1;15770;15767;15758:17;:::i;:::-;15750:25;;;;15802:17;15817:1;15814;15811;15802:17;:::i;:::-;15794:25;;;;15844:17;15859:1;15856;15853;15844:17;:::i;:::-;15893:2;15886:10;;15876:21;;;;15836:25;;-1:-1:-1;15886:10:0;-1:-1:-1;15964:1:0;15949:77;15974:2;15971:1;15968:9;15949:77;;;16007:17;16022:1;16019;16016;16007:17;:::i;:::-;15999:25;;-1:-1:-1;15999:25:0;-1:-1:-1;15992:1:0;15985:9;15949:77;;;15953:14;;;16053:5;:12;;;16050:86;;;16116:13;:11;:13::i;:::-;16109:20;;;;;16050:86;16141:10;;;:15;;16155:1;16141:15;;;;;16210:8;;;;-1:-1:-1;;16202:20:0;;-1:-1:-1;16202:7:0;:20::i;:::-;16188:34;-1:-1:-1;16245:10:0;16253:2;16245:10;;;;16306:1;16296:11;;;:26;;;16311:6;:11;;16321:1;16311:11;16296:26;16292:308;;;16531:62;16542:6;:11;;16552:1;16542:11;:20;;16560:2;16542:20;;;16556:1;16542:20;16531:62;;16591:1;16564:23;16567:4;16572:10;16567:15;16584:2;16564;:23::i;:::-;:28;;;;16531:10;:62::i;:::-;16524:69;;;;;;;16292:308;16801:15;;;;16628:9;;;;16749:4;16743:2;16735:10;;;16734:19;;;16801:15;16826:2;16818:10;;;16817:19;16801:36;;;;;;;;;;;;-1:-1:-1;16858:5:0;16873:11;;;;;:29;;;16888:6;:14;;16898:4;16888:14;16873:29;16869:636;;;16945:5;:15;;;16961:5;16945:22;;;;;;;;;;;;;;-1:-1:-1;;16998:4:0;16992:2;16984:10;;;16983:19;16869:636;;;17028:4;17019:6;:13;;;17015:490;;;17119:6;:13;;17129:3;17119:13;:30;;;;17136:6;:13;;17146:3;17136:13;17119:30;:47;;;;17153:6;:13;;17163:3;17153:13;17119:47;17115:181;;;17205:4;17210:6;17205:11;17200:16;;17115:181;;;17268:19;17271:4;17276:6;17271:11;17284:2;17268;:19::i;:::-;17263:24;;17115:181;17015:490;;;17322:4;17312:6;:14;;;;:32;;;;17330:6;:14;;17340:4;17330:14;17312:32;:50;;;;17348:6;:14;;17358:4;17348:14;17312:50;17308:197;;;17412:5;:15;;;17428:5;17412:22;;;;;;;;;;;;;17407:27;;17493:5;17485:13;;17308:197;17526:1;17516:6;:11;;;;:25;;;;;17540:1;17531:6;:10;;;17516:25;17515:42;;;;17546:6;:11;;17556:1;17546:11;17515:42;17511:107;;;17574:37;17587:6;17595:4;17601:5;17608:2;17574:12;:37::i;:::-;17567:44;;;;;;;;;;;17511:107;17643:13;17624:16;17763:4;17753:14;;;;17749:328;;17812:19;17815:4;17820:6;17815:11;17828:2;17812;:19::i;:::-;17806:25;;;;17858:10;17853:15;;17882:16;17853:15;17896:1;17882:7;:16::i;:::-;17876:22;;17920:4;17910:6;:14;;;;:32;;;;;17928:6;:14;;17938:4;17928:14;;17910:32;17906:165;;;17983:4;17971:16;;18061:1;18053:9;;17906:165;17749:328;;18094:10;18107:26;18115:4;18121:2;18125;18129:3;18107:7;:26::i;:::-;18136:10;18107:39;;;;-1:-1:-1;18224:4:0;18217:11;;;18248;;;:24;;;;;18271:1;18263:4;:9;;;;18248:24;:39;;;;;18283:4;18276;:11;;;18248:39;18244:589;;;18301:4;:9;;18309:1;18301:9;:22;;;;18314:4;:9;;18322:1;18314:9;18301:22;18297:102;;;18353:37;18364:4;:9;;18372:1;18364:9;:21;;18380:5;18364:21;;;18376:1;18364:21;18387:2;18353:10;:37::i;:::-;18346:44;;;;;;;;;;;;;;;18297:102;18411:4;:11;;18419:3;18411:11;18407:79;;;18449:28;18458:5;18465:2;18469:7;;;;18449:8;:28::i;18407:79::-;18497:4;:11;;18505:3;18497:11;18493:79;;;18535:28;18544:5;18551:2;18555:7;;;;;18535:8;:28::i;18493:79::-;18622:4;:11;;18630:3;18622:11;18618:58;;;18652:15;:13;:15::i;18618:58::-;18749:4;18741;:12;;;;:27;;;;;18764:4;18757;:11;;;18741:27;18737:90;;;18787:31;18798:4;18804:2;18808;18812:5;18787:10;:31::i;18737:90::-;18877:6;:14;;18887:4;18877:14;:28;;;;-1:-1:-1;18895:10:0;;;;;18877:28;18873:75;;;18940:1;18915:5;:15;;;18931:5;18915:22;;;;;;;;;:26;;;;:22;;;;;;:26;18873:75;18978:9;:26;;18991:13;18978:26;18974:74;;19014:27;19023:9;19034:1;19037:3;19014:8;:27::i;:::-;19113:26;19122:5;19129:3;19134:4;19113:8;:26::i;:::-;19106:33;;;;;;;;;;;;;14355:4789;;;;;;;:::o;2085:1331::-;2126:11;2254:176;;;2346:2;2342:13;;;2332:24;;2326:31;2315:43;;2378:13;;2409;;;2305:125::o;:::-;2449:4;2488;2482:11;2526:5;2550:21;2568:2;2564;2558:4;2550:21;:::i;:::-;2538:33;;;;2601:21;2619:2;2615;2609:4;2601:21;:::i;:::-;2589:33;;;;2656:20;2674:1;2670:2;2664:4;2656:20;:::i;:::-;2644:32;;;;2713:20;2731:1;2727:2;2721:4;2713:20;:::i;:::-;2701:32;;;;2758:20;2776:1;2772:2;2766:4;2758:20;:::i;:::-;2746:32;;;;2807:20;2825:1;2821:2;2815:4;2807:20;:::i;:::-;2795:32;;;;2852:20;2870:1;2866:2;2860:4;2852:20;:::i;:::-;2840:32;;;;2897:20;2915:1;2911:2;2905:4;2897:20;:::i;:::-;2885:32;;;;2944:20;2962:1;2958:2;2952:4;2944:20;:::i;:::-;2932:32;;;;2995:20;3013:1;3009:2;3003:4;2995:20;:::i;:::-;2983:32;;;;3044:20;3062:1;3058:2;3052:4;3044:20;:::i;:::-;3097:2;3087:13;;;;-1:-1:-1;3032:32:0;-1:-1:-1;3145:1:0;3130:84;3155:2;3152:1;3149:9;3130:84;;;3192:20;3210:1;3206:2;3200:4;3192:20;:::i;:::-;3180:32;;-1:-1:-1;3180:32:0;-1:-1:-1;3173:1:0;3166:9;3130:84;;;3134:14;3245:1;3241:2;3234:13;3290:5;3286:2;3282:14;3275:5;3270:27;3375:14;;;3358:32;;;-1:-1:-1;;2085:1331:0;;:::o;11757:1270::-;11828:10;11846:14;11863:23;11875:10;11863:11;:23::i;:::-;11846:40;;11922:1;11916:4;11912:12;11909:2;;;11937:1;11934;11927:12;11909:2;12039;12027:15;;;11990:20;12049:169;;;;12088:12;;;12174:2;12167:13;;;;12207:2;12194:16;;;12078:140::o;:::-;12244:4;12241:1;12237:12;12268:4;12391:1;12376:273;12401:2;12398:1;12395:9;12376:273;;;12500:2;12488:15;;;12449:20;12523:12;;;12537:1;12519:20;12548:42;;;;12604:1;12599:42;;;;12512:129;;12548:42;12565:23;12580:7;12574:4;12565:23;:::i;:::-;12557:31;;12548:42;;12599;12616:23;12634:4;12625:7;12616:23;:::i;:::-;12608:31;;12512:129;-1:-1:-1;;12419:1:0;12412:9;12376:273;;;12380:14;12677:4;12671:11;12656:26;;12746:7;12740:4;12737:17;12727:2;;12803:10;12800:1;12793:21;12833:2;12830:1;12823:13;12727:2;-1:-1:-1;;12949:2:0;12939:13;;12927:10;12923:30;12920:1;12916:38;12972:16;12990:10;12968:33;;-1:-1:-1;;11757:1270:0;;;;:::o;1825:256::-;1884:6;1915:14;;;;1923:5;;;;1915:14;;;;;;1914:21;;;;;1927:1;1966:2;:6;;;1960:13;;;;;1959:19;;1958:28;;;;;;;2008:8;;2007:14;1914:21;2053;;2073:1;2053:21;;;2064:6;2053:21;2041:8;;;;;:34;;-1:-1:-1;;;1825:256:0;;;;:::o;10429:401::-;10496:7;10511:18;;:::i;:::-;-1:-1:-1;10592:8:0;;;10617:12;;;10606:23;;;;;;;10635:19;;;;;10561:4;;10664:12;;;10660:140;;10713:6;10720:1;10713:8;10686:5;:15;;;10702:7;10686:24;;;;;;;;;:35;;;;:24;;;;;;:35;10660:140;10812:13;:11;:13::i;:::-;10805:20;10429:401;-1:-1:-1;;;;;10429:401:0:o;8271:1063::-;8364:7;8379:18;;:::i;:::-;-1:-1:-1;8429:4:0;8444:17;8490:1;8480:11;;;;;:26;;;8495:6;:11;;8505:1;8495:11;8480:26;8476:514;;;8529:9;8541:5;:15;;;8557:5;8541:22;;;;;;;;;;;;;8529:34;;8593:2;8587:8;;:2;:8;;;:23;;;;;8599:6;:11;;8609:1;8599:11;8587:23;8586:54;;;;8622:2;8616:8;;:2;:8;;;;:23;;;;;8628:6;:11;;8638:1;8628:11;8616:23;8571:69;;8476:514;;;;8657:6;:11;;8667:1;8657:11;8653:337;;;8700:1;8693:2;8687:14;;;;8672:29;;8653:337;;;8726:6;:11;;8736:1;8726:11;8722:268;;;8768:1;8762:2;8756:13;;;8741:28;;8722:268;;;8794:6;:11;;8804:1;8794:11;8790:200;;;8860:4;8854:2;8846:10;;;8845:19;8877:8;8873:42;;8914:1;8908:2;8902:13;;;8887:28;;8873:42;8936:3;:8;;8943:1;8936:8;8932:43;;;8974:1;8967:2;8961:14;;;;8946:29;;8932:43;8790:200;;9012:8;;;;;9037:12;;;;9026:23;;;;;9087:216;;;;9163:1;9142:19;9145:4;9150:6;9145:11;9158:2;9142;:19::i;:::-;:22;;;;;;;9128:37;;9137:1;9128:37;9113:52;:12;;;:52;9087:216;;;9260:12;;;;;9275:1;9260:16;9245:31;;;;9087:216;9316:13;:11;:13::i;:::-;9309:20;8271:1063;-1:-1:-1;;;;;;;;8271:1063:0:o;19148:4269::-;19235:6;19265:10;19273:2;19265:10;;;;;;19308:11;;19404:4;19395:13;;19391:3986;;;19505:1;19495:6;:11;;;;:27;;;;;19519:3;19510:6;:12;;;19495:27;19491:462;;;19538:6;:11;;19548:1;19538:11;19534:383;;;-1:-1:-1;19560:4:0;19534:383;;;19600:6;:11;;19610:1;19600:11;19596:321;;;-1:-1:-1;19622:4:0;19596:321;;;19658:6;:13;;19668:3;19658:13;19654:263;;;-1:-1:-1;19682:4:0;19654:263;;;19715:6;:13;;19725:3;19715:13;19711:206;;;-1:-1:-1;19739:4:0;19711:206;;;19773:6;:13;;19783:3;19773:13;19769:148;;;-1:-1:-1;19797:4:0;19769:148;;;19830:6;:13;;19840:3;19830:13;19826:91;;;-1:-1:-1;19854:4:0;19826:91;;;19886:6;:13;;19896:3;19886:13;19882:35;;;-1:-1:-1;19910:4:0;19882:35;19943:1;19934:10;;19491:462;19994:11;;;19990:1701;;20046:4;20041:1;20033:9;;;20032:18;20071:4;20033:9;20064:11;;;20060:588;;;20101:4;20093;:12;;;20089:549;;20116:2;20109:9;;;;;;;20089:549;20196:12;;;20192:446;;20219:11;;;;;;;;-1:-1:-1;20212:18:0;;-1:-1:-1;;20212:18:0;20192:446;20265:4;:12;;20273:4;20265:12;20261:377;;;20288:11;;;;;;;;-1:-1:-1;20281:18:0;;-1:-1:-1;;20281:18:0;20261:377;20334:4;:12;;20342:4;20334:12;20330:308;;;20357:25;20366:5;20360:11;;:2;:11;;;;20376:5;20373:2;:8;20357:2;:25::i;20330:308::-;20417:4;:12;;20425:4;20417:12;20413:225;;;-1:-1:-1;;;;20440:15:0;;;20450:4;20447:7;;20440:15;20433:22;;20413:225;20494:4;:12;;20502:4;20494:12;20490:148;;;-1:-1:-1;;;;20517:15:0;;;20527:4;20524:7;;20517:15;20510:22;;20490:148;20571:4;:12;;20579:4;20571:12;20567:71;;;20594:19;20603:2;20597:8;;:2;:8;;;;20610:2;20607;:5;20594:2;:19::i;20567:71::-;20736:4;:12;;20744:4;20736:12;:28;;;;20752:4;:12;;20760:4;20752:12;20736:28;20732:602;;;20778:2;20775;:5;20768:12;;;;;;;20732:602;20818:4;:12;;20826:4;20818:12;:28;;;;20834:4;:12;;20842:4;20834:12;20818:28;20814:520;;;20860:2;20857;:5;20850:12;;;;;;;20814:520;20900:4;:12;;20908:4;20900:12;20896:438;;;20926:2;20923;:5;20916:12;;;;;;;20896:438;20967:4;:12;;20975:4;20967:12;20963:371;;;20994:2;20991;:5;20983:14;;;;;;;20963:371;21033:4;:12;;21041:4;21033:12;21029:305;;;21060:2;21057;:5;21049:14;;;;;;;21029:305;21100:4;:12;;21108:4;21100:12;21096:238;;;-1:-1:-1;;;;21125:5:0;;;21123:8;21116:15;;21096:238;21167:4;:12;;21175:4;21167:12;21163:171;;;21216:2;21200:19;;21206:2;21200:19;;;:27;;21226:1;21200:27;;;21222:1;21200:27;21193:34;;;;;;;;;21163:171;21255:4;:12;;21263:4;21255:12;21251:83;;;21291:2;21288:5;;:2;:5;;;:13;;21300:1;21288:13;;21251:83;19990:1701;;;;21352:6;:13;;21362:3;21352:13;21348:343;;;21380:2;21376;:6;;;;21369:13;;;;;;21348:343;21408:6;:14;;21418:4;21408:14;21404:287;;;21451:4;:9;;21459:1;21451:9;21447:49;;;-1:-1:-1;;;21476:19:0;;;21462:34;;21447:49;21517:4;:12;;21525:4;21517:12;:28;;;;21533:4;:12;;21541:4;21533:12;21517:28;21513:170;;;21570:4;:12;;21578:4;21570:12;21566:26;;;21589:3;;;21566:26;21604:8;21618:45;21628:10;21625:13;;:18;21618:45;;21652:8;21647:3;21652:8;;;;;21647:3;21618:45;;;21671:1;-1:-1:-1;21664:8:0;;-1:-1:-1;;21664:8:0;21513:170;19391:3986;;;21716:4;21707:6;:13;;;21703:1674;;;21734:6;:14;;21744:4;21734:14;21730:776;;;21774:36;21790:2;21793:1;21790:4;21796:1;21789:8;21786:2;:11;21778:20;;:3;:20;;;;21802:4;21777:29;21808:1;21774:2;:36::i;:::-;21767:43;;;;;;21730:776;21829:6;:14;;21839:4;21829:14;21825:681;;;21869:39;21885:2;21888:1;21885:4;21891:1;21884:8;21881:2;:11;21873:20;;:3;:20;;;;21897:6;21872:31;21905:2;21869;:39::i;21825:681::-;21927:6;:14;;21937:4;21927:14;21923:583;;;-1:-1:-1;;;21974:17:0;21989:1;21986;21983:4;;21982:8;21974:17;;22015:32;;;22070:5;22065:10;;21974:17;;;;;22064:18;22057:25;;21923:583;22101:6;:14;;22111:4;22101:14;22097:409;;;22126:3;22119:10;;;;;;22097:409;22156:6;:14;;22166:4;22156:14;22152:354;;;22210:2;22213:1;22210:4;22216:1;22209:8;22206:2;:11;22198:20;;:3;:20;;;;22222:4;22197:29;22190:36;;;;;;22152:354;22245:6;:14;;22255:4;22245:14;22241:265;;;22299:2;22302:1;22299:4;22305:1;22298:8;22295:2;:11;22287:20;;:3;:20;;;;22311:6;22286:31;22279:38;;;;;;22241:265;22336:6;:14;;22346:4;22336:14;22332:174;;;-1:-1:-1;;;22383:20:0;22401:1;22398;22395:4;;22394:8;22391:2;:11;22383:20;;22427:35;;;22485:5;22480:10;;22383:20;;;;;22479:18;22472:25;;21703:1674;22522:6;:14;;22532:4;22522:14;22518:859;;;-1:-1:-1;;;22569:4:0;22565:26;22589:1;22586;22583:4;;22582:8;22579:2;:11;22565:26;;22633:21;;;22613:42;;;22671:10;;22566:7;;;22565:26;;22670:18;22663:25;;22518:859;22705:6;:14;;22715:4;22705:14;22701:676;;;-1:-1:-1;;;22752:6:0;22748:28;22774:1;22771;22768:4;;22767:8;22764:2;:11;22748:28;;22818:23;;;22798:44;;;22858:10;;22749:9;;;22748:28;;22857:18;22850:25;;22701:676;22892:6;:14;;22902:4;22892:14;22888:489;;;-1:-1:-1;;;22937:16:0;22951:1;22948;22945:4;;22944:8;22937:16;;22975:32;;;23029:5;23023:11;;22937:16;;;;;23022:19;23015:26;;22888:489;23058:6;:14;;23068:4;23058:14;23054:323;;;23095:2;23088:9;;;;;;23054:323;23114:6;:14;;23124:4;23114:14;23110:267;;;-1:-1:-1;;;23159:19:0;23176:1;23173;23170:4;;23169:8;23166:2;:11;23159:19;;23200:35;;;23257:5;23251:11;;23159:19;;;;;23250;23243:26;;23110:267;23286:6;:14;;23296:4;23286:14;23282:95;;;23311:3;23304:10;;;;;;23282:95;23337:6;:14;;23347:4;23337:14;23333:44;;;23362:2;23355:9;;;;;;23333:44;23383:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10834:455;10917:7;10932:18;;:::i;:::-;-1:-1:-1;10982:4:0;11016:2;11005:13;;;;10997:40;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11115:13;;;;;;;:28;;;11132:11;11115:28;11111:80;;;11181:3;11153:5;:15;;;11169:8;11153:25;;;;;;;;;:31;;;;:25;;;;;;:31;11111:80;11208:12;;;;;11197:23;;;;:8;;;:23;11256:1;11241:16;;;11226:31;;;11271:13;:11;:13::i;3420:4847::-;3463:7;3478:18;;:::i;:::-;-1:-1:-1;3563:15:0;;:18;;;;3528:4;3638:18;;;;3674;;;;3710;;;;;3528:4;;3543:17;;;;3638:18;3674;3739;;;3753:4;3739:18;3735:4375;;;3793:2;3810:4;3807:7;;:12;3803:98;;3887:4;3884:7;;3876:4;:16;3870:22;3803:98;3912:7;;;3908:105;;3936:10;;;;;3956:16;;;;;;;;3936:10;-1:-1:-1;3908:105:0;;;4002:2;3997:7;;3908:105;3735:4375;;;;4029:10;:18;;4043:4;4029:18;4025:4085;;;1458:10;4070:14;;4025:4085;;;4101:10;:18;;4115:4;4101:18;4097:4013;;;4165:1;4160:6;;4097:4013;;;4183:10;:18;;4197:4;4183:18;4179:3931;;;4246:4;4231:12;;;:19;4258:26;;;:14;;;:26;4299:13;:11;:13::i;:::-;4292:20;;;;;;;;;;;4179:3931;4329:10;:18;;4343:4;4329:18;4325:3785;;;4458:14;;;4454:1768;;;;;4549:22;;;1679:1;4549:22;4545:1677;;;4670:10;4683:27;4691:2;4696:10;4691:15;4708:1;4683:7;:27::i;:::-;4761:11;4792:6;;4812:17;;;;4831:20;;;;;4792:60;;;;;;;;;;;;;;;;;;;;4670:40;;-1:-1:-1;4761:11:0;;;;4792:6;;;;;:19;;:60;;;;;;;;;;;:6;:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;4792:60:0;;;;;;;;;-1:-1:-1;4792:60:0;-1:-1:-1;4965:1:0;4957:10;;5045:1;5041:17;;;5106;;;5103:2;;;5136:5;5126:15;;5103:2;;5205:6;5201:2;5198:14;5195:2;;;5225;5215:12;;5195:2;5317:3;5312:1;5304:6;5300:14;5295:3;5291:24;5287:34;5280:41;;5382:3;5378:1;5367:9;5363:17;5359:27;5352:34;;5492:1;5488;5484;5472:9;5469:1;5465:17;5461:25;5457:33;5453:41;5605:1;5601;5597;5588:6;5576:9;5573:1;5569:17;5565:30;5561:38;5557:46;5553:54;5535:72;;5691:10;5687:15;5681:4;5677:26;5669:34;;5793:3;5785:4;5781:9;5776:3;5772:19;5769:28;5762:35;;;;5873:33;5882:2;5887:10;5882:15;5899:1;5902:3;5873:8;:33::i;:::-;5916:20;;;:38;;;;;;;;;-1:-1:-1;4545:1677:0;;-1:-1:-1;;4545:1677:0;;6002:18;;;1602:1;6002:18;5998:224;;;6151:2;6146:7;;5998:224;;;6183:10;6178:15;;1750:3;6203:10;;5998:224;4325:3785;;;6238:10;:18;;6252:4;6238:18;6234:1876;;;6371:15;;;1533:1;6371:15;;:34;;-1:-1:-1;6390:15:0;;;1566:1;6390:15;6371:34;:57;;;-1:-1:-1;6409:19:0;;;1639:1;6409:19;6371:57;6367:1172;;;6445:2;6440:7;;6367:1172;;;6509:23;;;1720:1;6509:23;6505:1034;;;6564:10;6577:27;6585:2;6590:10;6585:15;6602:1;6577:7;:27::i;:::-;6668:17;;;;6564:40;;-1:-1:-1;6798:1:0;6790:10;;6878:1;6874:17;6939:13;;;6936:2;;;6961:5;6955:11;;6936:2;7205:14;;;7039:1;7201:22;;;7197:32;;;;7108:26;7132:1;7031:10;;;7112:18;;;7108:26;7193:43;7027:20;;7287:12;7337:17;;;:23;7393:1;7370:20;;;:24;7035:2;-1:-1:-1;7035:2:0;6505:1034;;6234:1876;7555:10;:18;;7569:4;7555:18;7551:559;;;7629:2;:7;;7635:1;7629:7;7625:479;;;7690:14;;;;;:40;;-1:-1:-1;7708:22:0;;;1679:1;7708:22;7690:40;:62;;;-1:-1:-1;7734:18:0;;;1602:1;7734:18;7690:62;7686:312;;;7771:1;7766:6;;7686:312;;;7805:15;;;1533:1;7805:15;;:34;;-1:-1:-1;7824:15:0;;;1566:1;7824:15;7805:34;:61;;;-1:-1:-1;7843:23:0;;;1720:1;7843:23;7805:61;:84;;;-1:-1:-1;7870:19:0;;;1639:1;7870:19;7805:84;7801:197;;;7908:1;7903:6;;7801:197;;7625:479;8027:10;8022:15;;1782:4;8047:11;;7625:479;8116:15;;;;;:23;;;;:18;;;;:23;;;;8145:15;;:23;;;:18;;;;:23;-1:-1:-1;8186:12:0;;;;8175:23;;;:8;;;:23;8234:1;8219:16;8204:31;;;;;8249:13;:11;:13::i;:::-;8242:20;;;;;;;;;3420:4847;:::o;9338:1087::-;9428:7;9443:18;;:::i;:::-;-1:-1:-1;9493:4:0;9508:10;9536:4;9528:12;;;;9524:732;;;-1:-1:-1;9548:8:0;;;;9524:732;;;9579:4;:12;;9587:4;9579:12;9575:681;;;9593:13;;;:8;;;:13;9575:681;;;9629:4;:12;;9637:4;9629:12;9625:631;;;-1:-1:-1;9649:8:0;;;;9625:631;;;9680:4;:12;;9688:4;9680:12;9676:580;;;9694:13;;;:8;;;:13;9676:580;;;9730:4;:12;;9738:4;9730:12;9726:530;;;9840:7;9797:16;9780;;;9797;;;;9780:33;9845:2;9840:7;;;;;9822:8;;;:26;9856:22;:8;;;:22;9726:530;;;9895:4;:12;;9903:4;9895:12;9891:365;;;9957:10;9946;;;9957;;;9946:21;9999:2;9994:7;;;;;9976:8;;;:26;10010:22;:8;;;:22;9891:365;;;10049:4;:12;;10057:4;10049:12;10045:211;;;10112:2;10096:19;;10102:2;10096:19;;;;;;;;10078:38;;:8;;;:38;10142:19;;;;;;;;;;;;;;10124:38;;:8;;;:38;10045:211;;;10179:4;:12;;10187:4;10179:12;10175:81;;;10223:2;10220:5;;:2;:5;;;;;;;;10209:16;;;;:8;;;:16;10244:5;;;;;;;;;;;;10233:16;;:8;;;:16;10175:81;10266:13;;;;10262:65;;10317:3;10289:5;:15;;;10305:8;10289:25;;;;;;;;;:31;;;;:25;;;;;;:31;10262:65;10344:12;;;;;10333:23;;;;:8;;;:23;10392:1;10377:16;;;10362:31;;;10407:13;:11;:13::i;:::-;10400:20;9338:1087;-1:-1:-1;;;;;;;9338:1087:0:o;13150:1145::-;13233:14;13250:23;13262:10;13250:11;:23::i;:::-;13233:40;;13309:1;13303:4;13299:12;13296:2;;;13324:1;13321;13314:12;13296:2;13432;13595:15;;;13450:2;13440:13;;13428:10;13424:30;13421:1;13417:38;13560:17;;;13377:20;;13545:10;13534:22;;;13530:27;13520:38;13517:61;13812:4;13809:1;13805:12;13959:1;13944:273;13969:2;13966:1;13963:9;13944:273;;;14068:2;14056:15;;;14017:20;14091:12;;;14105:1;14087:20;14116:42;;;;14172:1;14167:42;;;;14080:129;;14116:42;14133:23;14148:7;14142:4;14133:23;:::i;:::-;14125:31;;14116:42;;14167;14184:23;14202:4;14193:7;14184:23;:::i;:::-;14176:31;;14080:129;-1:-1:-1;;13987:1:0;13980:9;13944:273;;;-1:-1:-1;;14231:4:0;14224:18;-1:-1:-1;;;;13288:1003:0:o;11293:460::-;11568:19;;;11591:5;11568:29;11561:3;:37;;;11639:14;;11674;;11668:21;;;11660:69;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11735:13;11293:460;;;:::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;:::o"
func init() {
if err := json.Unmarshal([]byte(MIPSStorageLayoutJSON), MIPSStorageLayout); err != nil {
panic(err)
}
layouts["MIPS"] = MIPSStorageLayout
deployedBytecodes["MIPS"] = MIPSDeployedBin
}
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package bindings
import (
"errors"
"math/big"
"strings"
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
)
// Reference imports to suppress errors if they are not otherwise used.
var (
_ = errors.New
_ = big.NewInt
_ = strings.NewReader
_ = ethereum.NotFound
_ = bind.Bind
_ = common.Big1
_ = types.BloomLookup
_ = event.NewSubscription
)
// PreimageOracleMetaData contains all meta data concerning the PreimageOracle contract.
var PreimageOracleMetaData = &bind.MetaData{
ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"partOffset\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"part\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"size\",\"type\":\"uint256\"}],\"name\":\"cheat\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"partOffset\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"preimage\",\"type\":\"bytes\"}],\"name\":\"loadKeccak256PreimagePart\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"preimageLengths\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"preimagePartOk\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"preimageParts\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"offset\",\"type\":\"uint256\"}],\"name\":\"readPreimage\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"dat\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"datLen\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
Bin: "0x608060405234801561001057600080fd5b50610509806100206000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c8063e159261111610050578063e15926111461011b578063fe4ac08e14610130578063fef2b4ed146101a557600080fd5b806361238bde146100775780638542cf50146100b5578063e03110e1146100f3575b600080fd5b6100a26100853660046103b5565b600160209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b6100e36100c33660046103b5565b600260209081526000928352604080842090915290825290205460ff1681565b60405190151581526020016100ac565b6101066101013660046103b5565b6101c5565b604080519283526020830191909152016100ac565b61012e6101293660046103d7565b6102b6565b005b61012e61013e366004610453565b6000838152600260209081526040808320878452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091558684528252808320968352958152858220939093559283529082905291902055565b6100a26101b3366004610485565b60006020819052908152604090205481565b6000828152600260209081526040808320848452909152812054819060ff1661024e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f707265696d616765206d75737420657869737400000000000000000000000000604482015260640160405180910390fd5b506000838152602081815260409091205461026a8160086104cd565b6102758560206104cd565b1061029357836102868260086104cd565b61029091906104e5565b91505b506000938452600160209081526040808620948652939052919092205492909150565b6044356000806008830186106102cb57600080fd5b60c083901b6080526088838682378087017ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80151908490207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f02000000000000000000000000000000000000000000000000000000000000001760008181526002602090815260408083208b8452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811790915584845282528083209a83529981528982209390935590815290819052959095209190915550505050565b600080604083850312156103c857600080fd5b50508035926020909101359150565b6000806000604084860312156103ec57600080fd5b83359250602084013567ffffffffffffffff8082111561040b57600080fd5b818601915086601f83011261041f57600080fd5b81358181111561042e57600080fd5b87602082850101111561044057600080fd5b6020830194508093505050509250925092565b6000806000806080858703121561046957600080fd5b5050823594602084013594506040840135936060013592509050565b60006020828403121561049757600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082198211156104e0576104e061049e565b500190565b6000828210156104f7576104f761049e565b50039056fea164736f6c634300080f000a",
}
// PreimageOracleABI is the input ABI used to generate the binding from.
// Deprecated: Use PreimageOracleMetaData.ABI instead.
var PreimageOracleABI = PreimageOracleMetaData.ABI
// PreimageOracleBin is the compiled bytecode used for deploying new contracts.
// Deprecated: Use PreimageOracleMetaData.Bin instead.
var PreimageOracleBin = PreimageOracleMetaData.Bin
// DeployPreimageOracle deploys a new Ethereum contract, binding an instance of PreimageOracle to it.
func DeployPreimageOracle(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *PreimageOracle, error) {
parsed, err := PreimageOracleMetaData.GetAbi()
if err != nil {
return common.Address{}, nil, nil, err
}
if parsed == nil {
return common.Address{}, nil, nil, errors.New("GetABI returned nil")
}
address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(PreimageOracleBin), backend)
if err != nil {
return common.Address{}, nil, nil, err
}
return address, tx, &PreimageOracle{PreimageOracleCaller: PreimageOracleCaller{contract: contract}, PreimageOracleTransactor: PreimageOracleTransactor{contract: contract}, PreimageOracleFilterer: PreimageOracleFilterer{contract: contract}}, nil
}
// PreimageOracle is an auto generated Go binding around an Ethereum contract.
type PreimageOracle struct {
PreimageOracleCaller // Read-only binding to the contract
PreimageOracleTransactor // Write-only binding to the contract
PreimageOracleFilterer // Log filterer for contract events
}
// PreimageOracleCaller is an auto generated read-only Go binding around an Ethereum contract.
type PreimageOracleCaller struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// PreimageOracleTransactor is an auto generated write-only Go binding around an Ethereum contract.
type PreimageOracleTransactor struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// PreimageOracleFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
type PreimageOracleFilterer struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// PreimageOracleSession is an auto generated Go binding around an Ethereum contract,
// with pre-set call and transact options.
type PreimageOracleSession struct {
Contract *PreimageOracle // Generic contract binding to set the session for
CallOpts bind.CallOpts // Call options to use throughout this session
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
// PreimageOracleCallerSession is an auto generated read-only Go binding around an Ethereum contract,
// with pre-set call options.
type PreimageOracleCallerSession struct {
Contract *PreimageOracleCaller // Generic contract caller binding to set the session for
CallOpts bind.CallOpts // Call options to use throughout this session
}
// PreimageOracleTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
// with pre-set transact options.
type PreimageOracleTransactorSession struct {
Contract *PreimageOracleTransactor // Generic contract transactor binding to set the session for
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
// PreimageOracleRaw is an auto generated low-level Go binding around an Ethereum contract.
type PreimageOracleRaw struct {
Contract *PreimageOracle // Generic contract binding to access the raw methods on
}
// PreimageOracleCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
type PreimageOracleCallerRaw struct {
Contract *PreimageOracleCaller // Generic read-only contract binding to access the raw methods on
}
// PreimageOracleTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
type PreimageOracleTransactorRaw struct {
Contract *PreimageOracleTransactor // Generic write-only contract binding to access the raw methods on
}
// NewPreimageOracle creates a new instance of PreimageOracle, bound to a specific deployed contract.
func NewPreimageOracle(address common.Address, backend bind.ContractBackend) (*PreimageOracle, error) {
contract, err := bindPreimageOracle(address, backend, backend, backend)
if err != nil {
return nil, err
}
return &PreimageOracle{PreimageOracleCaller: PreimageOracleCaller{contract: contract}, PreimageOracleTransactor: PreimageOracleTransactor{contract: contract}, PreimageOracleFilterer: PreimageOracleFilterer{contract: contract}}, nil
}
// NewPreimageOracleCaller creates a new read-only instance of PreimageOracle, bound to a specific deployed contract.
func NewPreimageOracleCaller(address common.Address, caller bind.ContractCaller) (*PreimageOracleCaller, error) {
contract, err := bindPreimageOracle(address, caller, nil, nil)
if err != nil {
return nil, err
}
return &PreimageOracleCaller{contract: contract}, nil
}
// NewPreimageOracleTransactor creates a new write-only instance of PreimageOracle, bound to a specific deployed contract.
func NewPreimageOracleTransactor(address common.Address, transactor bind.ContractTransactor) (*PreimageOracleTransactor, error) {
contract, err := bindPreimageOracle(address, nil, transactor, nil)
if err != nil {
return nil, err
}
return &PreimageOracleTransactor{contract: contract}, nil
}
// NewPreimageOracleFilterer creates a new log filterer instance of PreimageOracle, bound to a specific deployed contract.
func NewPreimageOracleFilterer(address common.Address, filterer bind.ContractFilterer) (*PreimageOracleFilterer, error) {
contract, err := bindPreimageOracle(address, nil, nil, filterer)
if err != nil {
return nil, err
}
return &PreimageOracleFilterer{contract: contract}, nil
}
// bindPreimageOracle binds a generic wrapper to an already deployed contract.
func bindPreimageOracle(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
parsed, err := abi.JSON(strings.NewReader(PreimageOracleABI))
if err != nil {
return nil, err
}
return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil
}
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_PreimageOracle *PreimageOracleRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
return _PreimageOracle.Contract.PreimageOracleCaller.contract.Call(opts, result, method, params...)
}
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_PreimageOracle *PreimageOracleRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
return _PreimageOracle.Contract.PreimageOracleTransactor.contract.Transfer(opts)
}
// Transact invokes the (paid) contract method with params as input values.
func (_PreimageOracle *PreimageOracleRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
return _PreimageOracle.Contract.PreimageOracleTransactor.contract.Transact(opts, method, params...)
}
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_PreimageOracle *PreimageOracleCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
return _PreimageOracle.Contract.contract.Call(opts, result, method, params...)
}
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_PreimageOracle *PreimageOracleTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
return _PreimageOracle.Contract.contract.Transfer(opts)
}
// Transact invokes the (paid) contract method with params as input values.
func (_PreimageOracle *PreimageOracleTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
return _PreimageOracle.Contract.contract.Transact(opts, method, params...)
}
// PreimageLengths is a free data retrieval call binding the contract method 0xfef2b4ed.
//
// Solidity: function preimageLengths(bytes32 ) view returns(uint256)
func (_PreimageOracle *PreimageOracleCaller) PreimageLengths(opts *bind.CallOpts, arg0 [32]byte) (*big.Int, error) {
var out []interface{}
err := _PreimageOracle.contract.Call(opts, &out, "preimageLengths", arg0)
if err != nil {
return *new(*big.Int), err
}
out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
return out0, err
}
// PreimageLengths is a free data retrieval call binding the contract method 0xfef2b4ed.
//
// Solidity: function preimageLengths(bytes32 ) view returns(uint256)
func (_PreimageOracle *PreimageOracleSession) PreimageLengths(arg0 [32]byte) (*big.Int, error) {
return _PreimageOracle.Contract.PreimageLengths(&_PreimageOracle.CallOpts, arg0)
}
// PreimageLengths is a free data retrieval call binding the contract method 0xfef2b4ed.
//
// Solidity: function preimageLengths(bytes32 ) view returns(uint256)
func (_PreimageOracle *PreimageOracleCallerSession) PreimageLengths(arg0 [32]byte) (*big.Int, error) {
return _PreimageOracle.Contract.PreimageLengths(&_PreimageOracle.CallOpts, arg0)
}
// PreimagePartOk is a free data retrieval call binding the contract method 0x8542cf50.
//
// Solidity: function preimagePartOk(bytes32 , uint256 ) view returns(bool)
func (_PreimageOracle *PreimageOracleCaller) PreimagePartOk(opts *bind.CallOpts, arg0 [32]byte, arg1 *big.Int) (bool, error) {
var out []interface{}
err := _PreimageOracle.contract.Call(opts, &out, "preimagePartOk", arg0, arg1)
if err != nil {
return *new(bool), err
}
out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
return out0, err
}
// PreimagePartOk is a free data retrieval call binding the contract method 0x8542cf50.
//
// Solidity: function preimagePartOk(bytes32 , uint256 ) view returns(bool)
func (_PreimageOracle *PreimageOracleSession) PreimagePartOk(arg0 [32]byte, arg1 *big.Int) (bool, error) {
return _PreimageOracle.Contract.PreimagePartOk(&_PreimageOracle.CallOpts, arg0, arg1)
}
// PreimagePartOk is a free data retrieval call binding the contract method 0x8542cf50.
//
// Solidity: function preimagePartOk(bytes32 , uint256 ) view returns(bool)
func (_PreimageOracle *PreimageOracleCallerSession) PreimagePartOk(arg0 [32]byte, arg1 *big.Int) (bool, error) {
return _PreimageOracle.Contract.PreimagePartOk(&_PreimageOracle.CallOpts, arg0, arg1)
}
// PreimageParts is a free data retrieval call binding the contract method 0x61238bde.
//
// Solidity: function preimageParts(bytes32 , uint256 ) view returns(bytes32)
func (_PreimageOracle *PreimageOracleCaller) PreimageParts(opts *bind.CallOpts, arg0 [32]byte, arg1 *big.Int) ([32]byte, error) {
var out []interface{}
err := _PreimageOracle.contract.Call(opts, &out, "preimageParts", arg0, arg1)
if err != nil {
return *new([32]byte), err
}
out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte)
return out0, err
}
// PreimageParts is a free data retrieval call binding the contract method 0x61238bde.
//
// Solidity: function preimageParts(bytes32 , uint256 ) view returns(bytes32)
func (_PreimageOracle *PreimageOracleSession) PreimageParts(arg0 [32]byte, arg1 *big.Int) ([32]byte, error) {
return _PreimageOracle.Contract.PreimageParts(&_PreimageOracle.CallOpts, arg0, arg1)
}
// PreimageParts is a free data retrieval call binding the contract method 0x61238bde.
//
// Solidity: function preimageParts(bytes32 , uint256 ) view returns(bytes32)
func (_PreimageOracle *PreimageOracleCallerSession) PreimageParts(arg0 [32]byte, arg1 *big.Int) ([32]byte, error) {
return _PreimageOracle.Contract.PreimageParts(&_PreimageOracle.CallOpts, arg0, arg1)
}
// ReadPreimage is a free data retrieval call binding the contract method 0xe03110e1.
//
// Solidity: function readPreimage(bytes32 key, uint256 offset) view returns(bytes32 dat, uint256 datLen)
func (_PreimageOracle *PreimageOracleCaller) ReadPreimage(opts *bind.CallOpts, key [32]byte, offset *big.Int) (struct {
Dat [32]byte
DatLen *big.Int
}, error) {
var out []interface{}
err := _PreimageOracle.contract.Call(opts, &out, "readPreimage", key, offset)
outstruct := new(struct {
Dat [32]byte
DatLen *big.Int
})
if err != nil {
return *outstruct, err
}
outstruct.Dat = *abi.ConvertType(out[0], new([32]byte)).(*[32]byte)
outstruct.DatLen = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int)
return *outstruct, err
}
// ReadPreimage is a free data retrieval call binding the contract method 0xe03110e1.
//
// Solidity: function readPreimage(bytes32 key, uint256 offset) view returns(bytes32 dat, uint256 datLen)
func (_PreimageOracle *PreimageOracleSession) ReadPreimage(key [32]byte, offset *big.Int) (struct {
Dat [32]byte
DatLen *big.Int
}, error) {
return _PreimageOracle.Contract.ReadPreimage(&_PreimageOracle.CallOpts, key, offset)
}
// ReadPreimage is a free data retrieval call binding the contract method 0xe03110e1.
//
// Solidity: function readPreimage(bytes32 key, uint256 offset) view returns(bytes32 dat, uint256 datLen)
func (_PreimageOracle *PreimageOracleCallerSession) ReadPreimage(key [32]byte, offset *big.Int) (struct {
Dat [32]byte
DatLen *big.Int
}, error) {
return _PreimageOracle.Contract.ReadPreimage(&_PreimageOracle.CallOpts, key, offset)
}
// Cheat is a paid mutator transaction binding the contract method 0xfe4ac08e.
//
// Solidity: function cheat(uint256 partOffset, bytes32 key, bytes32 part, uint256 size) returns()
func (_PreimageOracle *PreimageOracleTransactor) Cheat(opts *bind.TransactOpts, partOffset *big.Int, key [32]byte, part [32]byte, size *big.Int) (*types.Transaction, error) {
return _PreimageOracle.contract.Transact(opts, "cheat", partOffset, key, part, size)
}
// Cheat is a paid mutator transaction binding the contract method 0xfe4ac08e.
//
// Solidity: function cheat(uint256 partOffset, bytes32 key, bytes32 part, uint256 size) returns()
func (_PreimageOracle *PreimageOracleSession) Cheat(partOffset *big.Int, key [32]byte, part [32]byte, size *big.Int) (*types.Transaction, error) {
return _PreimageOracle.Contract.Cheat(&_PreimageOracle.TransactOpts, partOffset, key, part, size)
}
// Cheat is a paid mutator transaction binding the contract method 0xfe4ac08e.
//
// Solidity: function cheat(uint256 partOffset, bytes32 key, bytes32 part, uint256 size) returns()
func (_PreimageOracle *PreimageOracleTransactorSession) Cheat(partOffset *big.Int, key [32]byte, part [32]byte, size *big.Int) (*types.Transaction, error) {
return _PreimageOracle.Contract.Cheat(&_PreimageOracle.TransactOpts, partOffset, key, part, size)
}
// LoadKeccak256PreimagePart is a paid mutator transaction binding the contract method 0xe1592611.
//
// Solidity: function loadKeccak256PreimagePart(uint256 partOffset, bytes preimage) returns()
func (_PreimageOracle *PreimageOracleTransactor) LoadKeccak256PreimagePart(opts *bind.TransactOpts, partOffset *big.Int, preimage []byte) (*types.Transaction, error) {
return _PreimageOracle.contract.Transact(opts, "loadKeccak256PreimagePart", partOffset, preimage)
}
// LoadKeccak256PreimagePart is a paid mutator transaction binding the contract method 0xe1592611.
//
// Solidity: function loadKeccak256PreimagePart(uint256 partOffset, bytes preimage) returns()
func (_PreimageOracle *PreimageOracleSession) LoadKeccak256PreimagePart(partOffset *big.Int, preimage []byte) (*types.Transaction, error) {
return _PreimageOracle.Contract.LoadKeccak256PreimagePart(&_PreimageOracle.TransactOpts, partOffset, preimage)
}
// LoadKeccak256PreimagePart is a paid mutator transaction binding the contract method 0xe1592611.
//
// Solidity: function loadKeccak256PreimagePart(uint256 partOffset, bytes preimage) returns()
func (_PreimageOracle *PreimageOracleTransactorSession) LoadKeccak256PreimagePart(partOffset *big.Int, preimage []byte) (*types.Transaction, error) {
return _PreimageOracle.Contract.LoadKeccak256PreimagePart(&_PreimageOracle.TransactOpts, partOffset, preimage)
}
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package bindings
import (
"encoding/json"
"github.com/ethereum-optimism/optimism/op-bindings/solc"
)
const PreimageOracleStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"contracts/cannon/PreimageOracle.sol:PreimageOracle\",\"label\":\"preimageLengths\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_mapping(t_bytes32,t_uint256)\"},{\"astId\":1001,\"contract\":\"contracts/cannon/PreimageOracle.sol:PreimageOracle\",\"label\":\"preimageParts\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_mapping(t_bytes32,t_mapping(t_uint256,t_bytes32))\"},{\"astId\":1002,\"contract\":\"contracts/cannon/PreimageOracle.sol:PreimageOracle\",\"label\":\"preimagePartOk\",\"offset\":0,\"slot\":\"2\",\"type\":\"t_mapping(t_bytes32,t_mapping(t_uint256,t_bool))\"}],\"types\":{\"t_bool\":{\"encoding\":\"inplace\",\"label\":\"bool\",\"numberOfBytes\":\"1\"},\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_mapping(t_bytes32,t_mapping(t_uint256,t_bool))\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e mapping(uint256 =\u003e bool))\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_mapping(t_uint256,t_bool)\"},\"t_mapping(t_bytes32,t_mapping(t_uint256,t_bytes32))\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e mapping(uint256 =\u003e bytes32))\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_mapping(t_uint256,t_bytes32)\"},\"t_mapping(t_bytes32,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(bytes32 =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_bytes32\",\"value\":\"t_uint256\"},\"t_mapping(t_uint256,t_bool)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e bool)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_bool\"},\"t_mapping(t_uint256,t_bytes32)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e bytes32)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_bytes32\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"}}}"
var PreimageOracleStorageLayout = new(solc.StorageLayout)
var PreimageOracleDeployedBin = "0x608060405234801561001057600080fd5b50600436106100725760003560e01c8063e159261111610050578063e15926111461011b578063fe4ac08e14610130578063fef2b4ed146101a557600080fd5b806361238bde146100775780638542cf50146100b5578063e03110e1146100f3575b600080fd5b6100a26100853660046103b5565b600160209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b6100e36100c33660046103b5565b600260209081526000928352604080842090915290825290205460ff1681565b60405190151581526020016100ac565b6101066101013660046103b5565b6101c5565b604080519283526020830191909152016100ac565b61012e6101293660046103d7565b6102b6565b005b61012e61013e366004610453565b6000838152600260209081526040808320878452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091558684528252808320968352958152858220939093559283529082905291902055565b6100a26101b3366004610485565b60006020819052908152604090205481565b6000828152600260209081526040808320848452909152812054819060ff1661024e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f707265696d616765206d75737420657869737400000000000000000000000000604482015260640160405180910390fd5b506000838152602081815260409091205461026a8160086104cd565b6102758560206104cd565b1061029357836102868260086104cd565b61029091906104e5565b91505b506000938452600160209081526040808620948652939052919092205492909150565b6044356000806008830186106102cb57600080fd5b60c083901b6080526088838682378087017ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80151908490207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f02000000000000000000000000000000000000000000000000000000000000001760008181526002602090815260408083208b8452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811790915584845282528083209a83529981528982209390935590815290819052959095209190915550505050565b600080604083850312156103c857600080fd5b50508035926020909101359150565b6000806000604084860312156103ec57600080fd5b83359250602084013567ffffffffffffffff8082111561040b57600080fd5b818601915086601f83011261041f57600080fd5b81358181111561042e57600080fd5b87602082850101111561044057600080fd5b6020830194508093505050509250925092565b6000806000806080858703121561046957600080fd5b5050823594602084013594506040840135936060013592509050565b60006020828403121561049757600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082198211156104e0576104e061049e565b500190565b6000828210156104f7576104f761049e565b50039056fea164736f6c634300080f000a"
var PreimageOracleDeployedSourceMap = "57:2945:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;143:68;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;413:25:1;;;401:2;386:18;143:68:0;;;;;;;;217:66;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;614:14:1;;607:22;589:41;;577:2;562:18;217:66:0;449:187:1;290:454:0;;;;;;:::i;:::-;;:::i;:::-;;;;815:25:1;;;871:2;856:18;;849:34;;;;788:18;290:454:0;641:248:1;1537:1463:0;;;;;;:::i;:::-;;:::i;:::-;;1086:262;;;;;;:::i;:::-;1219:19;;;;:14;:19;;;;;;;;:31;;;;;;;;:38;;;;1253:4;1219:38;;;;;;1267:18;;;;;;;;:30;;;;;;;;;:37;;;;1314:20;;;;;;;;;;:27;1086:262;87:50;;;;;;:::i;:::-;;;;;;;;;;;;;;;290:454;388:11;439:19;;;:14;:19;;;;;;;;:27;;;;;;;;;388:11;;439:27;;431:59;;;;;;;2517:2:1;431:59:0;;;2499:21:1;2556:2;2536:18;;;2529:30;2595:21;2575:18;;;2568:49;2634:18;;431:59:0;;;;;;;;-1:-1:-1;521:14:0;538:20;;;509:2;538:20;;;;;;;;631:10;538:20;640:1;631:10;:::i;:::-;616:11;:6;625:2;616:11;:::i;:::-;:25;612:84;;679:6;666:10;:6;675:1;666:10;:::i;:::-;:19;;;;:::i;:::-;657:28;;612:84;-1:-1:-1;711:18:0;;;;:13;:18;;;;;;;;:26;;;;;;;;;;;;290:454;;-1:-1:-1;290:454:0:o;1537:1463::-;1831:4;1818:18;1636:12;;1966:1;1956:12;;1941:28;;1931:84;;1999:1;1996;1989:12;1931:84;2258:3;2254:14;;;2158:4;2242:27;2289:11;2263:4;2408:15;2289:11;2390:40;2620:28;;;2624:11;2620:28;2614:35;2671:20;;;;2818:19;2811:27;2840:11;2808:44;2871:19;;;;2849:1;2871:19;;;;;;;;:31;;;;;;;;:38;;;;2905:4;2871:38;;;;;;2919:18;;;;;;;;:30;;;;;;;;;:37;;;;2966:20;;;;;;;;;;;:27;;;;-1:-1:-1;;;;1537:1463:0:o;14:248:1:-;82:6;90;143:2;131:9;122:7;118:23;114:32;111:52;;;159:1;156;149:12;111:52;-1:-1:-1;;182:23:1;;;252:2;237:18;;;224:32;;-1:-1:-1;14:248:1:o;894:659::-;973:6;981;989;1042:2;1030:9;1021:7;1017:23;1013:32;1010:52;;;1058:1;1055;1048:12;1010:52;1094:9;1081:23;1071:33;;1155:2;1144:9;1140:18;1127:32;1178:18;1219:2;1211:6;1208:14;1205:34;;;1235:1;1232;1225:12;1205:34;1273:6;1262:9;1258:22;1248:32;;1318:7;1311:4;1307:2;1303:13;1299:27;1289:55;;1340:1;1337;1330:12;1289:55;1380:2;1367:16;1406:2;1398:6;1395:14;1392:34;;;1422:1;1419;1412:12;1392:34;1467:7;1462:2;1453:6;1449:2;1445:15;1441:24;1438:37;1435:57;;;1488:1;1485;1478:12;1435:57;1519:2;1515;1511:11;1501:21;;1541:6;1531:16;;;;;894:659;;;;;:::o;1558:385::-;1644:6;1652;1660;1668;1721:3;1709:9;1700:7;1696:23;1692:33;1689:53;;;1738:1;1735;1728:12;1689:53;-1:-1:-1;;1761:23:1;;;1831:2;1816:18;;1803:32;;-1:-1:-1;1882:2:1;1867:18;;1854:32;;1933:2;1918:18;1905:32;;-1:-1:-1;1558:385:1;-1:-1:-1;1558:385:1:o;1948:180::-;2007:6;2060:2;2048:9;2039:7;2035:23;2031:32;2028:52;;;2076:1;2073;2066:12;2028:52;-1:-1:-1;2099:23:1;;1948:180;-1:-1:-1;1948:180:1:o;2663:184::-;2715:77;2712:1;2705:88;2812:4;2809:1;2802:15;2836:4;2833:1;2826:15;2852:128;2892:3;2923:1;2919:6;2916:1;2913:13;2910:39;;;2929:18;;:::i;:::-;-1:-1:-1;2965:9:1;;2852:128::o;2985:125::-;3025:4;3053:1;3050;3047:8;3044:34;;;3058:18;;:::i;:::-;-1:-1:-1;3095:9:1;;2985:125::o"
func init() {
if err := json.Unmarshal([]byte(PreimageOracleStorageLayoutJSON), PreimageOracleStorageLayout); err != nil {
panic(err)
}
layouts["PreimageOracle"] = PreimageOracleStorageLayout
deployedBytecodes["PreimageOracle"] = PreimageOracleDeployedBin
}
...@@ -2,9 +2,11 @@ package main ...@@ -2,9 +2,11 @@ package main
import ( import (
"encoding/json" "encoding/json"
"errors"
"flag" "flag"
"log" "log"
"os" "os"
"path"
"path/filepath" "path/filepath"
"strings" "strings"
"text/template" "text/template"
...@@ -14,29 +16,45 @@ import ( ...@@ -14,29 +16,45 @@ import (
) )
type flags struct { type flags struct {
ArtifactsDir string ArtifactsDir string
Contracts string ForgeArtifacts string
OutDir string Contracts string
Package string SourceMaps string
OutDir string
Package string
} }
type data struct { type data struct {
Name string Name string
StorageLayout string StorageLayout string
DeployedBin string DeployedBin string
Package string Package string
DeployedSourceMap string
}
type forgeArtifact struct {
DeployedBytecode struct {
SourceMap string `json:"sourceMap"`
} `json:"deployedBytecode"`
} }
func main() { func main() {
var f flags var f flags
flag.StringVar(&f.ArtifactsDir, "artifacts", "", "Comma-separated list of directories containing artifacts and build info") flag.StringVar(&f.ArtifactsDir, "artifacts", "", "Comma-separated list of directories containing artifacts and build info")
flag.StringVar(&f.ForgeArtifacts, "forge-artifacts", "", "Forge artifacts directory, to load sourcemaps from, if available")
flag.StringVar(&f.OutDir, "out", "", "Output directory to put code in") flag.StringVar(&f.OutDir, "out", "", "Output directory to put code in")
flag.StringVar(&f.Contracts, "contracts", "", "Comma-separated list of contracts to generate code for") flag.StringVar(&f.Contracts, "contracts", "", "Comma-separated list of contracts to generate code for")
flag.StringVar(&f.SourceMaps, "source-maps", "", "Comma-separated list of contracts to generate source-maps for")
flag.StringVar(&f.Package, "package", "artifacts", "Go package name") flag.StringVar(&f.Package, "package", "artifacts", "Go package name")
flag.Parse() flag.Parse()
artifacts := strings.Split(f.ArtifactsDir, ",") artifacts := strings.Split(f.ArtifactsDir, ",")
contracts := strings.Split(f.Contracts, ",") contracts := strings.Split(f.Contracts, ",")
sourceMaps := strings.Split(f.SourceMaps, ",")
sourceMapsSet := make(map[string]struct{})
for _, k := range sourceMaps {
sourceMapsSet[k] = struct{}{}
}
if len(artifacts) == 0 { if len(artifacts) == 0 {
log.Fatalf("must define a list of artifacts") log.Fatalf("must define a list of artifacts")
...@@ -71,11 +89,28 @@ func main() { ...@@ -71,11 +89,28 @@ func main() {
} }
serStr := strings.Replace(string(ser), "\"", "\\\"", -1) serStr := strings.Replace(string(ser), "\"", "\\\"", -1)
deployedSourceMap := ""
if _, ok := sourceMapsSet[name]; ok {
// directory has .sol extension
forgeArtifactData, err := os.ReadFile(path.Join(f.ForgeArtifacts, name+".sol", name+".json"))
if errors.Is(err, os.ErrNotExist) {
log.Printf("cannot find forge-artifact with source-map data of %q\n", name)
}
if err == nil {
var artifact forgeArtifact
if err := json.Unmarshal(forgeArtifactData, &artifact); err != nil {
log.Fatalf("failed to parse forge artifact of %q: %v\n", name, err)
}
deployedSourceMap = artifact.DeployedBytecode.SourceMap
}
}
d := data{ d := data{
Name: name, Name: name,
StorageLayout: serStr, StorageLayout: serStr,
DeployedBin: art.DeployedBytecode.String(), DeployedBin: art.DeployedBytecode.String(),
Package: f.Package, Package: f.Package,
DeployedSourceMap: deployedSourceMap,
} }
fname := filepath.Join(f.OutDir, strings.ToLower(name)+"_more.go") fname := filepath.Join(f.OutDir, strings.ToLower(name)+"_more.go")
...@@ -112,7 +147,9 @@ const {{.Name}}StorageLayoutJSON = "{{.StorageLayout}}" ...@@ -112,7 +147,9 @@ const {{.Name}}StorageLayoutJSON = "{{.StorageLayout}}"
var {{.Name}}StorageLayout = new(solc.StorageLayout) var {{.Name}}StorageLayout = new(solc.StorageLayout)
var {{.Name}}DeployedBin = "{{.DeployedBin}}" var {{.Name}}DeployedBin = "{{.DeployedBin}}"
{{if .DeployedSourceMap}}
var {{.Name}}DeployedSourceMap = "{{.DeployedSourceMap}}"
{{end}}
func init() { func init() {
if err := json.Unmarshal([]byte({{.Name}}StorageLayoutJSON), {{.Name}}StorageLayout); err != nil { if err := json.Unmarshal([]byte({{.Name}}StorageLayoutJSON), {{.Name}}StorageLayout); err != nil {
panic(err) panic(err)
......
package srcmap
import (
"fmt"
"io"
"math/big"
"os"
"strconv"
"strings"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
)
type LineCol struct {
Line uint32
Col uint32
}
type InstrMapping struct {
S int32 // start offset in bytes within source (negative when non-existent!)
L int32 // length in bytes within source (negative when non-existent!)
F int32 // file index of source (negative when non-existent!)
J byte // jump type (i=into, o=out, -=regular)
M int32 // modifier depth
}
func parseInstrMapping(last InstrMapping, v string) (InstrMapping, error) {
data := strings.Split(v, ":")
out := last
if len(data) < 1 {
return out, nil
}
if len(data) > 5 {
return out, fmt.Errorf("unexpected length: %d", len(data))
}
var err error
parse := func(x string) int32 {
p, e := strconv.ParseInt(x, 10, 32)
err = e
return int32(p)
}
if data[0] != "" {
out.S = parse(data[0])
}
if len(data) < 2 || err != nil {
return out, err
}
if data[1] != "" {
out.L = parse(data[1])
}
if len(data) < 3 || err != nil {
return out, err
}
if data[2] != "" {
out.F = parse(data[2])
}
if len(data) < 4 || err != nil {
return out, err
}
if data[3] != "" {
out.J = data[3][0]
}
if len(data) < 5 || err != nil {
return out, err
}
if data[4] != "" {
out.M = parse(data[4])
}
return out, err
}
type SourceMap struct {
// source names
Sources []string
// per source, source offset -> line/col
PosData [][]LineCol
// per bytecode byte, byte index -> instr
Instr []InstrMapping
}
func (s *SourceMap) Info(pc uint64) (source string, line uint32, col uint32) {
instr := s.Instr[pc]
if instr.F < 0 {
return "generated", 0, 0
}
if instr.F >= int32(len(s.Sources)) {
source = "unknown"
return
}
source = s.Sources[instr.F]
if instr.S < 0 {
return
}
if s.PosData[instr.F] == nil { // when the source file is known to be unavailable
return
}
lc := s.PosData[instr.F][instr.S]
line = lc.Line
col = lc.Col
return
}
func (s *SourceMap) FormattedInfo(pc uint64) string {
f, l, c := s.Info(pc)
return fmt.Sprintf("%s:%d:%d", f, l, c)
}
// ParseSourceMap parses a solidity sourcemap: mapping bytecode indices to source references.
// See https://docs.soliditylang.org/en/latest/internals/source_mappings.html
//
// Sources is the list of source files, which will be read from the filesystem
// to transform token numbers into line/column numbers.
// The sources are as referenced in the source-map by index.
// Not all sources are necessary, some indices may be unknown.
func ParseSourceMap(sources []string, bytecode []byte, sourceMap string) (*SourceMap, error) {
instructions := strings.Split(sourceMap, ";")
srcMap := &SourceMap{
Sources: sources,
PosData: make([][]LineCol, 0, len(sources)),
Instr: make([]InstrMapping, 0, len(bytecode)),
}
// map source code position byte offsets to line/column pairs
for i, s := range sources {
if strings.HasPrefix(s, "~") {
srcMap.PosData = append(srcMap.PosData, nil)
continue
}
dat, err := os.ReadFile(s)
if err != nil {
return nil, fmt.Errorf("failed to read source %d %q: %w", i, s, err)
}
datStr := string(dat)
out := make([]LineCol, len(datStr))
line := uint32(1)
lastLinePos := uint32(0)
for i, b := range datStr { // iterate the utf8 or the bytes?
col := uint32(i) - lastLinePos
out[i] = LineCol{Line: line, Col: col}
if b == '\n' {
lastLinePos = uint32(i)
line += 1
}
}
srcMap.PosData = append(srcMap.PosData, out)
}
instIndex := 0
// bytecode offset to instruction
lastInstr := InstrMapping{}
for i := 0; i < len(bytecode); {
inst := bytecode[i]
instLen := 1
if inst >= 0x60 && inst <= 0x7f { // push instructions
pushDataLen := inst - 0x60 + 1
instLen += int(pushDataLen)
}
var instMapping string
if instIndex >= len(instructions) {
// truncated source-map? Or some instruction that's longer than we accounted for?
// probably the contract-metadata bytes that are not accounted for in source map
} else {
instMapping = instructions[instIndex]
}
m, err := parseInstrMapping(lastInstr, instMapping)
if err != nil {
return nil, fmt.Errorf("failed to parse instr element in source map: %w", err)
}
for j := 0; j < instLen; j++ {
srcMap.Instr = append(srcMap.Instr, m)
}
i += instLen
instIndex += 1
}
return srcMap, nil
}
func NewSourceMapTracer(srcMaps map[common.Address]*SourceMap, out io.Writer) *SourceMapTracer {
return &SourceMapTracer{srcMaps, out}
}
type SourceMapTracer struct {
srcMaps map[common.Address]*SourceMap
out io.Writer
}
func (s *SourceMapTracer) CaptureTxStart(gasLimit uint64) {}
func (s *SourceMapTracer) CaptureTxEnd(restGas uint64) {}
func (s *SourceMapTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
}
func (s *SourceMapTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {}
func (s *SourceMapTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
}
func (s *SourceMapTracer) CaptureExit(output []byte, gasUsed uint64, err error) {}
func (s *SourceMapTracer) info(codeAddr *common.Address, pc uint64) string {
info := "non-contract"
if codeAddr != nil {
srcMap, ok := s.srcMaps[*codeAddr]
if ok {
info = srcMap.FormattedInfo(pc)
} else {
info = "unknown-contract"
}
}
return info
}
func (s *SourceMapTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
fmt.Fprintf(s.out, "%-40s : pc %x opcode %s\n", s.info(scope.Contract.CodeAddr, pc), pc, op.String())
}
func (s *SourceMapTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
fmt.Fprintf(s.out, "%-40s: pc %x opcode %s FAULT %v\n", s.info(scope.Contract.CodeAddr, pc), pc, op.String(), err)
fmt.Println("----")
fmt.Fprintf(s.out, "calldata: %x\n", scope.Contract.Input)
fmt.Println("----")
fmt.Fprintf(s.out, "memory: %x\n", scope.Memory.Data())
fmt.Println("----")
fmt.Fprintf(s.out, "stack:\n")
stack := scope.Stack.Data()
for i := range stack {
fmt.Fprintf(s.out, "%3d: %x\n", -i, stack[len(stack)-1-i].Bytes32())
}
}
var _ vm.EVMLogger = (*SourceMapTracer)(nil)
package srcmap
import (
"strings"
"testing"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
)
func TestSourcemap(t *testing.T) {
sourcePath := "../../packages/contracts-bedrock/contracts/cannon/MIPS.sol"
deployedByteCode := hexutil.MustDecode(bindings.MIPSDeployedBin)
srcMap, err := ParseSourceMap(
[]string{sourcePath},
deployedByteCode,
bindings.MIPSDeployedSourceMap)
require.NoError(t, err)
for i := 0; i < len(deployedByteCode); i++ {
info := srcMap.FormattedInfo(uint64(i))
if !strings.HasPrefix(info, "generated:") && !strings.HasPrefix(info, sourcePath) {
t.Fatalf("unexpected info: %q", info)
}
}
}
package main
import (
"github.com/ethereum-optimism/optimism/op-challenger/fault"
)
func main() {
// Example 1
// abcdefgh
// abcdexyz
// go left to d, then right to f, then left to e
p := fault.Position{}
p.Print(3)
p.Attack()
p.Print(3)
p.Defend()
p.Print(3)
p.Attack()
p.Print(3)
// Trace Position is 0000 Trace Depth is: 0 Trace Index is: 8
// Trace Position is 0000 Trace Depth is: 1 Trace Index is: 4
// Trace Position is 0010 Trace Depth is: 2 Trace Index is: 6
// Trace Position is 0100 Trace Depth is: 3 Trace Index is: 5
// Example 2
// abcdefgh
// abqrstuv
// go left r, then left to b, then right to q
p = fault.Position{}
p.Print(3)
p.Attack()
p.Print(3)
p.Attack()
p.Print(3)
p.Defend()
p.Print(3)
// Trace Position is 0000 Trace Depth is: 0 Trace Index is: 8
// Trace Position is 0000 Trace Depth is: 1 Trace Index is: 4
// Trace Position is 0000 Trace Depth is: 2 Trace Index is: 2
// Trace Position is 0010 Trace Depth is: 3 Trace Index is: 3
}
package fault
import "fmt"
// Position is a golang wrapper around the dispute game Position type.
// Depth refers to how many bisection steps have occurred.
// IndexAtDepth refers to the path that the bisection has taken
// where 1 = goes right & 0 = goes left.
type Position struct {
Depth int
IndexAtDepth int
}
// TraceIndex calculates the what the index of the claim value
// would be inside the trace.
func (p *Position) TraceIndex(maxDepth int) int {
lo := 0
hi := 1 << maxDepth
mid := hi
path := p.IndexAtDepth
for i := p.Depth - 1; i >= 0; i-- {
mid = (lo + hi) / 2
mask := 1 << i
if path&mask == mask {
lo = mid
} else {
hi = mid
}
}
return mid
}
func (p *Position) move(right bool) {
p.Depth++
p.IndexAtDepth = (p.IndexAtDepth << 1) | boolToInt(right)
}
func boolToInt(b bool) int {
if b {
return 1
} else {
return 0
}
}
func (p *Position) parent() {
p.Depth--
p.IndexAtDepth = p.IndexAtDepth >> 1
}
func (p *Position) Attack() {
p.move(false)
}
func (p *Position) Defend() {
p.parent()
p.move(true)
p.move(false)
}
func (p *Position) Print(maxDepth int) {
fmt.Printf("Trace Position is %04b\tTrace Depth is: %d\tTrace Index is: %d\n", p.IndexAtDepth, p.Depth, p.TraceIndex(maxDepth))
}
package fault
import (
"errors"
"github.com/ethereum/go-ethereum/common"
)
var (
ErrNegativeIndex = errors.New("index cannot be negative")
ErrIndexTooLarge = errors.New("index is larger than the maximum index")
)
// TraceProvider is a generic way to get a claim value at a specific
// step in the trace.
type TraceProvider interface {
Get(i int) (common.Hash, error)
}
type Claim struct {
Value common.Hash
Position
}
type Response struct {
Attack bool // note: can we flip this to true == going right / defending??
Value common.Hash
}
...@@ -118,14 +118,6 @@ func (n *NodeP2P) init(resourcesCtx context.Context, rollupCfg *rollup.Config, l ...@@ -118,14 +118,6 @@ func (n *NodeP2P) init(resourcesCtx context.Context, rollupCfg *rollup.Config, l
} }
n.store = eps n.store = eps
n.scorer = NewScorer(rollupCfg, eps, metrics, log) n.scorer = NewScorer(rollupCfg, eps, metrics, log)
n.host.Network().Notify(&network.NotifyBundle{
ConnectedF: func(_ network.Network, conn network.Conn) {
n.scorer.OnConnect(conn.RemotePeer())
},
DisconnectedF: func(_ network.Network, conn network.Conn) {
n.scorer.OnDisconnect(conn.RemotePeer())
},
})
// notify of any new connections/streams/etc. // notify of any new connections/streams/etc.
n.host.Network().Notify(NewNetworkNotifier(log, metrics)) n.host.Network().Notify(NewNetworkNotifier(log, metrics))
// note: the IDDelta functionality was removed from libP2P, and no longer needs to be explicitly disabled. // note: the IDDelta functionality was removed from libP2P, and no longer needs to be explicitly disabled.
......
...@@ -35,8 +35,6 @@ type Peerstore interface { ...@@ -35,8 +35,6 @@ type Peerstore interface {
// Scorer is a peer scorer that scores peers based on application-specific metrics. // Scorer is a peer scorer that scores peers based on application-specific metrics.
type Scorer interface { type Scorer interface {
OnConnect(id peer.ID)
OnDisconnect(id peer.ID)
SnapshotHook() pubsub.ExtendedPeerScoreInspectFn SnapshotHook() pubsub.ExtendedPeerScoreInspectFn
} }
...@@ -86,13 +84,3 @@ func (s *scorer) SnapshotHook() pubsub.ExtendedPeerScoreInspectFn { ...@@ -86,13 +84,3 @@ func (s *scorer) SnapshotHook() pubsub.ExtendedPeerScoreInspectFn {
s.metricer.SetPeerScores(allScores) s.metricer.SetPeerScores(allScores)
} }
} }
// OnConnect is called when a peer connects.
func (s *scorer) OnConnect(id peer.ID) {
// TODO(CLI-4003): apply decay to scores, based on last connection time
}
// OnDisconnect is called when a peer disconnects.
func (s *scorer) OnDisconnect(id peer.ID) {
// TODO(CLI-4003): persist disconnect-time
}
...@@ -38,28 +38,6 @@ func TestPeerScorer(t *testing.T) { ...@@ -38,28 +38,6 @@ func TestPeerScorer(t *testing.T) {
suite.Run(t, new(PeerScorerTestSuite)) suite.Run(t, new(PeerScorerTestSuite))
} }
// TestScorer_OnConnect ensures we can call the OnConnect method on the peer scorer.
func (testSuite *PeerScorerTestSuite) TestScorer_OnConnect() {
scorer := p2p.NewScorer(
&rollup.Config{L2ChainID: big.NewInt(123)},
testSuite.mockStore,
testSuite.mockMetricer,
testSuite.logger,
)
scorer.OnConnect(peer.ID("alice"))
}
// TestScorer_OnDisconnect ensures we can call the OnDisconnect method on the peer scorer.
func (testSuite *PeerScorerTestSuite) TestScorer_OnDisconnect() {
scorer := p2p.NewScorer(
&rollup.Config{L2ChainID: big.NewInt(123)},
testSuite.mockStore,
testSuite.mockMetricer,
testSuite.logger,
)
scorer.OnDisconnect(peer.ID("alice"))
}
// TestScorer_SnapshotHook tests running the snapshot hook on the peer scorer. // TestScorer_SnapshotHook tests running the snapshot hook on the peer scorer.
func (testSuite *PeerScorerTestSuite) TestScorer_SnapshotHook() { func (testSuite *PeerScorerTestSuite) TestScorer_SnapshotHook() {
scorer := p2p.NewScorer( scorer := p2p.NewScorer(
......
...@@ -2,6 +2,7 @@ package store ...@@ -2,6 +2,7 @@ package store
import ( import (
"errors" "errors"
"math"
"net" "net"
"time" "time"
...@@ -27,9 +28,59 @@ func (g GossipScores) Apply(rec *scoreRecord) { ...@@ -27,9 +28,59 @@ func (g GossipScores) Apply(rec *scoreRecord) {
rec.PeerScores.Gossip = g rec.PeerScores.Gossip = g
} }
type ReqRespScores struct {
ValidResponses float64 `json:"validResponses"`
ErrorResponses float64 `json:"errorResponses"`
RejectedPayloads float64 `json:"rejectedPayloads"`
}
type IncrementValidResponses struct {
Cap float64
}
func (i IncrementValidResponses) Apply(rec *scoreRecord) {
rec.PeerScores.ReqResp.ValidResponses = math.Min(rec.PeerScores.ReqResp.ValidResponses+1, i.Cap)
}
type IncrementErrorResponses struct {
Cap float64
}
func (i IncrementErrorResponses) Apply(rec *scoreRecord) {
rec.PeerScores.ReqResp.ErrorResponses = math.Min(rec.PeerScores.ReqResp.ErrorResponses+1, i.Cap)
}
type IncrementRejectedPayloads struct {
Cap float64
}
func (i IncrementRejectedPayloads) Apply(rec *scoreRecord) {
rec.PeerScores.ReqResp.RejectedPayloads = math.Min(rec.PeerScores.ReqResp.RejectedPayloads+1, i.Cap)
}
type DecayApplicationScores struct {
ValidResponseDecay float64
ErrorResponseDecay float64
RejectedPayloadDecay float64
DecayToZero float64
}
func (d *DecayApplicationScores) Apply(rec *scoreRecord) {
decay := func(value float64, decay float64) float64 {
value *= decay
if value < d.DecayToZero {
return 0
}
return value
}
rec.PeerScores.ReqResp.ValidResponses = decay(rec.PeerScores.ReqResp.ValidResponses, d.ValidResponseDecay)
rec.PeerScores.ReqResp.ErrorResponses = decay(rec.PeerScores.ReqResp.ErrorResponses, d.ErrorResponseDecay)
rec.PeerScores.ReqResp.RejectedPayloads = decay(rec.PeerScores.ReqResp.RejectedPayloads, d.RejectedPayloadDecay)
}
type PeerScores struct { type PeerScores struct {
Gossip GossipScores `json:"gossip"` Gossip GossipScores `json:"gossip"`
ReqRespSync float64 `json:"reqRespSync"` ReqResp ReqRespScores `json:"reqResp"`
} }
// ScoreDatastore defines a type-safe API for getting and setting libp2p peer score information // ScoreDatastore defines a type-safe API for getting and setting libp2p peer score information
......
...@@ -45,6 +45,88 @@ func TestUpdateGossipScore(t *testing.T) { ...@@ -45,6 +45,88 @@ func TestUpdateGossipScore(t *testing.T) {
assertPeerScores(t, store, id, PeerScores{Gossip: GossipScores{Total: score}}) assertPeerScores(t, store, id, PeerScores{Gossip: GossipScores{Total: score}})
} }
func TestIncrementValidResponses(t *testing.T) {
id := peer.ID("aaaa")
store := createMemoryStore(t)
inc := IncrementValidResponses{Cap: 2.1}
setScoreRequired(t, store, id, inc)
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{ValidResponses: 1}})
setScoreRequired(t, store, id, inc)
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{ValidResponses: 2}})
setScoreRequired(t, store, id, inc)
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{ValidResponses: 2.1}})
}
func TestIncrementErrorResponses(t *testing.T) {
id := peer.ID("aaaa")
store := createMemoryStore(t)
inc := IncrementErrorResponses{Cap: 2.1}
setScoreRequired(t, store, id, inc)
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{ErrorResponses: 1}})
setScoreRequired(t, store, id, inc)
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{ErrorResponses: 2}})
setScoreRequired(t, store, id, inc)
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{ErrorResponses: 2.1}})
}
func TestIncrementRejectedPayloads(t *testing.T) {
id := peer.ID("aaaa")
store := createMemoryStore(t)
inc := IncrementRejectedPayloads{Cap: 2.1}
setScoreRequired(t, store, id, inc)
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{RejectedPayloads: 1}})
setScoreRequired(t, store, id, inc)
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{RejectedPayloads: 2}})
setScoreRequired(t, store, id, inc)
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{RejectedPayloads: 2.1}})
}
func TestDecayApplicationScores(t *testing.T) {
id := peer.ID("aaaa")
store := createMemoryStore(t)
for i := 0; i < 10; i++ {
setScoreRequired(t, store, id, IncrementValidResponses{Cap: 100})
setScoreRequired(t, store, id, IncrementErrorResponses{Cap: 100})
setScoreRequired(t, store, id, IncrementRejectedPayloads{Cap: 100})
}
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{
ValidResponses: 10,
ErrorResponses: 10,
RejectedPayloads: 10,
}})
setScoreRequired(t, store, id, &DecayApplicationScores{
ValidResponseDecay: 0.8,
ErrorResponseDecay: 0.4,
RejectedPayloadDecay: 0.5,
DecayToZero: 0.1,
})
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{
ValidResponses: 10 * 0.8,
ErrorResponses: 10 * 0.4,
RejectedPayloads: 10 * 0.5,
}})
// Should be set to exactly zero when below DecayToZero
setScoreRequired(t, store, id, &DecayApplicationScores{
ValidResponseDecay: 0.8,
ErrorResponseDecay: 0.4,
RejectedPayloadDecay: 0.5,
DecayToZero: 5,
})
assertPeerScores(t, store, id, PeerScores{ReqResp: ReqRespScores{
ValidResponses: 10 * 0.8 * 0.8, // Not yet below 5 so preserved
ErrorResponses: 0,
RejectedPayloads: 0,
}})
}
func TestStoreScoresForMultiplePeers(t *testing.T) { func TestStoreScoresForMultiplePeers(t *testing.T) {
id1 := peer.ID("aaaa") id1 := peer.ID("aaaa")
id2 := peer.ID("bbbb") id2 := peer.ID("bbbb")
...@@ -215,7 +297,7 @@ func createPeerstoreWithBacking(t *testing.T, store *sync.MutexDatastore) Extend ...@@ -215,7 +297,7 @@ func createPeerstoreWithBacking(t *testing.T, store *sync.MutexDatastore) Extend
return eps return eps
} }
func setScoreRequired(t *testing.T, store ScoreDatastore, id peer.ID, diff *GossipScores) { func setScoreRequired(t *testing.T, store ScoreDatastore, id peer.ID, diff ScoreDiff) {
_, err := store.SetScore(id, diff) _, err := store.SetScore(id, diff)
require.NoError(t, err) require.NoError(t, err)
} }
...@@ -45,7 +45,31 @@ func TestParseHistoricSerializationsV0(t *testing.T) { ...@@ -45,7 +45,31 @@ func TestParseHistoricSerializationsV0(t *testing.T) {
IPColocationFactor: 12.34, IPColocationFactor: 12.34,
BehavioralPenalty: 56.78, BehavioralPenalty: 56.78,
}, },
ReqRespSync: 123456, ReqResp: ReqRespScores{},
},
LastUpdate: 1923841,
},
},
{
data: `{"peerScores":{"gossip":{"total":1234.52382,"blocks":{"timeInMesh":1234,"firstMessageDeliveries":12,"meshMessageDeliveries":34,"invalidMessageDeliveries":56},"IPColocationFactor":12.34,"behavioralPenalty":56.78},"reqResp":{"validResponses":99,"errorResponses":88,"rejectedPayloads":77}},"lastUpdate":1923841}`,
expected: scoreRecord{
PeerScores: PeerScores{
Gossip: GossipScores{
Total: 1234.52382,
Blocks: TopicScores{
TimeInMesh: 1234,
FirstMessageDeliveries: 12,
MeshMessageDeliveries: 34,
InvalidMessageDeliveries: 56,
},
IPColocationFactor: 12.34,
BehavioralPenalty: 56.78,
},
ReqResp: ReqRespScores{
ValidResponses: 99,
ErrorResponses: 88,
RejectedPayloads: 77,
},
}, },
LastUpdate: 1923841, LastUpdate: 1923841,
}, },
......
# op-preimage
`op-preimage` offers simple Go bindings to interact as client or sever over the Pre-image Oracle ABI.
Read more about the Preimage Oracle in the [specs](../specs/fault-proof.md).
See [op-program](../op-program) and [Cannon client examples](../cannon/example) for client-side usage.
See [Cannon `mipsevm`](../cannon/mipsevm) for server-side usage.
package preimage
import (
"io"
"os"
)
// FileChannel is a unidirectional channel for file I/O
type FileChannel interface {
io.ReadWriteCloser
// Reader returns the file that is used for reading.
Reader() *os.File
// Writer returns the file that is used for writing.
Writer() *os.File
}
type ReadWritePair struct {
r *os.File
w *os.File
}
// NewReadWritePair creates a new FileChannel that uses the given files
func NewReadWritePair(r *os.File, w *os.File) *ReadWritePair {
return &ReadWritePair{r: r, w: w}
}
func (rw *ReadWritePair) Read(p []byte) (int, error) {
return rw.r.Read(p)
}
func (rw *ReadWritePair) Write(p []byte) (int, error) {
return rw.w.Write(p)
}
func (rw *ReadWritePair) Reader() *os.File {
return rw.r
}
func (rw *ReadWritePair) Writer() *os.File {
return rw.w
}
func (rw *ReadWritePair) Close() error {
if err := rw.r.Close(); err != nil {
return err
}
return rw.w.Close()
}
// CreateBidirectionalChannel creates a pair of FileChannels that are connected to each other.
func CreateBidirectionalChannel() (FileChannel, FileChannel, error) {
ar, bw, err := os.Pipe()
if err != nil {
return nil, nil, err
}
br, aw, err := os.Pipe()
if err != nil {
return nil, nil, err
}
return NewReadWritePair(ar, aw), NewReadWritePair(br, bw), nil
}
const (
HClientRFd = 3
HClientWFd = 4
PClientRFd = 5
PClientWFd = 6
)
func ClientHinterChannel() *ReadWritePair {
r := os.NewFile(HClientRFd, "preimage-hint-read")
w := os.NewFile(HClientWFd, "preimage-hint-write")
return NewReadWritePair(r, w)
}
// ClientPreimageChannel returns a FileChannel for the preimage oracle in a detached context
func ClientPreimageChannel() *ReadWritePair {
r := os.NewFile(PClientRFd, "preimage-oracle-read")
w := os.NewFile(PClientWFd, "preimage-oracle-write")
return NewReadWritePair(r, w)
}
package preimage
import "golang.org/x/crypto/sha3"
func Keccak256(v []byte) (out [32]byte) {
s := sha3.NewLegacyKeccak256()
s.Write(v)
s.Sum(out[:0])
return
}
...@@ -2,14 +2,13 @@ package preimage ...@@ -2,14 +2,13 @@ package preimage
import ( import (
"encoding/binary" "encoding/binary"
"encoding/hex"
"github.com/ethereum/go-ethereum/common"
) )
type Key interface { type Key interface {
// PreimageKey changes the Key commitment into a // PreimageKey changes the Key commitment into a
// 32-byte type-prefixed preimage key. // 32-byte type-prefixed preimage key.
PreimageKey() common.Hash PreimageKey() [32]byte
} }
type Oracle interface { type Oracle interface {
...@@ -40,27 +39,27 @@ const ( ...@@ -40,27 +39,27 @@ const (
// LocalIndexKey is a key local to the program, indexing a special program input. // LocalIndexKey is a key local to the program, indexing a special program input.
type LocalIndexKey uint64 type LocalIndexKey uint64
func (k LocalIndexKey) PreimageKey() (out common.Hash) { func (k LocalIndexKey) PreimageKey() (out [32]byte) {
out[0] = byte(LocalKeyType) out[0] = byte(LocalKeyType)
binary.BigEndian.PutUint64(out[24:], uint64(k)) binary.BigEndian.PutUint64(out[24:], uint64(k))
return return
} }
// Keccak256Key wraps a keccak256 hash to use it as a typed pre-image key. // Keccak256Key wraps a keccak256 hash to use it as a typed pre-image key.
type Keccak256Key common.Hash type Keccak256Key [32]byte
func (k Keccak256Key) PreimageKey() (out common.Hash) { func (k Keccak256Key) PreimageKey() (out [32]byte) {
out = common.Hash(k) // copy the keccak hash out = k // copy the keccak hash
out[0] = byte(Keccak256KeyType) // apply prefix out[0] = byte(Keccak256KeyType) // apply prefix
return return
} }
func (k Keccak256Key) String() string { func (k Keccak256Key) String() string {
return common.Hash(k).String() return "0x" + hex.EncodeToString(k[:])
} }
func (k Keccak256Key) TerminalString() string { func (k Keccak256Key) TerminalString() string {
return common.Hash(k).String() return "0x" + hex.EncodeToString(k[:])
} }
// Hint is an interface to enable any program type to function as a hint, // Hint is an interface to enable any program type to function as a hint,
......
...@@ -4,8 +4,6 @@ import ( ...@@ -4,8 +4,6 @@ import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"io" "io"
"github.com/ethereum/go-ethereum/common"
) )
// OracleClient implements the Oracle by writing the pre-image key to the given stream, // OracleClient implements the Oracle by writing the pre-image key to the given stream,
...@@ -47,10 +45,10 @@ func NewOracleServer(rw io.ReadWriter) *OracleServer { ...@@ -47,10 +45,10 @@ func NewOracleServer(rw io.ReadWriter) *OracleServer {
return &OracleServer{rw: rw} return &OracleServer{rw: rw}
} }
type PreimageGetter func(key common.Hash) ([]byte, error) type PreimageGetter func(key [32]byte) ([]byte, error)
func (o *OracleServer) NextPreimageRequest(getPreimage PreimageGetter) error { func (o *OracleServer) NextPreimageRequest(getPreimage PreimageGetter) error {
var key common.Hash var key [32]byte
if _, err := io.ReadFull(o.rw, key[:]); err != nil { if _, err := io.ReadFull(o.rw, key[:]); err != nil {
if err == io.EOF { if err == io.EOF {
return io.EOF return io.EOF
......
...@@ -8,8 +8,6 @@ import ( ...@@ -8,8 +8,6 @@ import (
"sync" "sync"
"testing" "testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
...@@ -30,13 +28,13 @@ func TestOracle(t *testing.T) { ...@@ -30,13 +28,13 @@ func TestOracle(t *testing.T) {
cl := NewOracleClient(a) cl := NewOracleClient(a)
srv := NewOracleServer(b) srv := NewOracleServer(b)
preimageByHash := make(map[common.Hash][]byte) preimageByHash := make(map[[32]byte][]byte)
for _, p := range preimages { for _, p := range preimages {
k := Keccak256Key(crypto.Keccak256Hash(p)) k := Keccak256Key(Keccak256(p))
preimageByHash[k.PreimageKey()] = p preimageByHash[k.PreimageKey()] = p
} }
for _, p := range preimages { for _, p := range preimages {
k := Keccak256Key(crypto.Keccak256Hash(p)) k := Keccak256Key(Keccak256(p))
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(2) wg.Add(2)
...@@ -49,7 +47,7 @@ func TestOracle(t *testing.T) { ...@@ -49,7 +47,7 @@ func TestOracle(t *testing.T) {
}(k, p) }(k, p)
go func() { go func() {
err := srv.NextPreimageRequest(func(key common.Hash) ([]byte, error) { err := srv.NextPreimageRequest(func(key [32]byte) ([]byte, error) {
dat, ok := preimageByHash[key] dat, ok := preimageByHash[key]
if !ok { if !ok {
return nil, fmt.Errorf("cannot find %s", key) return nil, fmt.Errorf("cannot find %s", key)
......
...@@ -6,6 +6,7 @@ RUN apk add --no-cache make gcc musl-dev linux-headers git jq bash ...@@ -6,6 +6,7 @@ RUN apk add --no-cache make gcc musl-dev linux-headers git jq bash
# build op-program with the shared go.mod & go.sum files # build op-program with the shared go.mod & go.sum files
COPY ./op-program /app/op-program COPY ./op-program /app/op-program
COPY ./op-preimage /app/op-preimage
COPY ./op-node /app/op-node COPY ./op-node /app/op-node
COPY ./op-chain-ops /app/op-chain-ops COPY ./op-chain-ops /app/op-chain-ops
COPY ./op-service /app/op-service COPY ./op-service /app/op-service
......
...@@ -5,7 +5,7 @@ import ( ...@@ -5,7 +5,7 @@ import (
"encoding/json" "encoding/json"
"github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-program/preimage" preimage "github.com/ethereum-optimism/optimism/op-preimage"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
......
...@@ -6,7 +6,7 @@ import ( ...@@ -6,7 +6,7 @@ import (
"testing" "testing"
"github.com/ethereum-optimism/optimism/op-node/chaincfg" "github.com/ethereum-optimism/optimism/op-node/chaincfg"
"github.com/ethereum-optimism/optimism/op-program/preimage" preimage "github.com/ethereum-optimism/optimism/op-preimage"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
......
...@@ -3,7 +3,7 @@ package l1 ...@@ -3,7 +3,7 @@ package l1
import ( import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum-optimism/optimism/op-program/preimage" preimage "github.com/ethereum-optimism/optimism/op-preimage"
) )
const ( const (
......
...@@ -8,8 +8,8 @@ import ( ...@@ -8,8 +8,8 @@ import (
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum-optimism/optimism/op-node/eth" "github.com/ethereum-optimism/optimism/op-node/eth"
preimage "github.com/ethereum-optimism/optimism/op-preimage"
"github.com/ethereum-optimism/optimism/op-program/client/mpt" "github.com/ethereum-optimism/optimism/op-program/client/mpt"
"github.com/ethereum-optimism/optimism/op-program/preimage"
) )
type Oracle interface { type Oracle interface {
......
...@@ -15,8 +15,8 @@ import ( ...@@ -15,8 +15,8 @@ import (
"github.com/ethereum-optimism/optimism/op-node/eth" "github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/testutils" "github.com/ethereum-optimism/optimism/op-node/testutils"
preimage "github.com/ethereum-optimism/optimism/op-preimage"
"github.com/ethereum-optimism/optimism/op-program/client/mpt" "github.com/ethereum-optimism/optimism/op-program/client/mpt"
"github.com/ethereum-optimism/optimism/op-program/preimage"
) )
// testBlock tests that the given block with receipts can be passed through the preimage oracle. // testBlock tests that the given block with receipts can be passed through the preimage oracle.
......
...@@ -3,7 +3,7 @@ package l2 ...@@ -3,7 +3,7 @@ package l2
import ( import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum-optimism/optimism/op-program/preimage" preimage "github.com/ethereum-optimism/optimism/op-preimage"
) )
const ( const (
......
...@@ -8,8 +8,8 @@ import ( ...@@ -8,8 +8,8 @@ import (
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum-optimism/optimism/op-node/eth" "github.com/ethereum-optimism/optimism/op-node/eth"
preimage "github.com/ethereum-optimism/optimism/op-preimage"
"github.com/ethereum-optimism/optimism/op-program/client/mpt" "github.com/ethereum-optimism/optimism/op-program/client/mpt"
"github.com/ethereum-optimism/optimism/op-program/preimage"
) )
// StateOracle defines the high-level API used to retrieve L2 state data pre-images // StateOracle defines the high-level API used to retrieve L2 state data pre-images
......
...@@ -15,8 +15,8 @@ import ( ...@@ -15,8 +15,8 @@ import (
"github.com/ethereum-optimism/optimism/op-node/eth" "github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/testutils" "github.com/ethereum-optimism/optimism/op-node/testutils"
preimage "github.com/ethereum-optimism/optimism/op-preimage"
"github.com/ethereum-optimism/optimism/op-program/client/mpt" "github.com/ethereum-optimism/optimism/op-program/client/mpt"
"github.com/ethereum-optimism/optimism/op-program/preimage"
) )
func mockPreimageOracle(t *testing.T) (po *PreimageOracle, hintsMock *mock.Mock, preimages map[common.Hash][]byte) { func mockPreimageOracle(t *testing.T) (po *PreimageOracle, hintsMock *mock.Mock, preimages map[common.Hash][]byte) {
......
...@@ -13,11 +13,11 @@ import ( ...@@ -13,11 +13,11 @@ import (
"github.com/ethereum-optimism/optimism/op-node/eth" "github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup"
preimage "github.com/ethereum-optimism/optimism/op-preimage"
cldr "github.com/ethereum-optimism/optimism/op-program/client/driver" cldr "github.com/ethereum-optimism/optimism/op-program/client/driver"
"github.com/ethereum-optimism/optimism/op-program/client/l1" "github.com/ethereum-optimism/optimism/op-program/client/l1"
"github.com/ethereum-optimism/optimism/op-program/client/l2" "github.com/ethereum-optimism/optimism/op-program/client/l2"
oppio "github.com/ethereum-optimism/optimism/op-program/io" oppio "github.com/ethereum-optimism/optimism/op-program/io"
"github.com/ethereum-optimism/optimism/op-program/preimage"
) )
// Main executes the client program in a detached context and exits the current process. // Main executes the client program in a detached context and exits the current process.
......
...@@ -13,6 +13,7 @@ import ( ...@@ -13,6 +13,7 @@ import (
"github.com/ethereum-optimism/optimism/op-node/chaincfg" "github.com/ethereum-optimism/optimism/op-node/chaincfg"
"github.com/ethereum-optimism/optimism/op-node/client" "github.com/ethereum-optimism/optimism/op-node/client"
"github.com/ethereum-optimism/optimism/op-node/sources" "github.com/ethereum-optimism/optimism/op-node/sources"
preimage "github.com/ethereum-optimism/optimism/op-preimage"
cl "github.com/ethereum-optimism/optimism/op-program/client" cl "github.com/ethereum-optimism/optimism/op-program/client"
"github.com/ethereum-optimism/optimism/op-program/client/driver" "github.com/ethereum-optimism/optimism/op-program/client/driver"
"github.com/ethereum-optimism/optimism/op-program/host/config" "github.com/ethereum-optimism/optimism/op-program/host/config"
...@@ -20,7 +21,6 @@ import ( ...@@ -20,7 +21,6 @@ import (
"github.com/ethereum-optimism/optimism/op-program/host/kvstore" "github.com/ethereum-optimism/optimism/op-program/host/kvstore"
"github.com/ethereum-optimism/optimism/op-program/host/prefetcher" "github.com/ethereum-optimism/optimism/op-program/host/prefetcher"
oppio "github.com/ethereum-optimism/optimism/op-program/io" oppio "github.com/ethereum-optimism/optimism/op-program/io"
"github.com/ethereum-optimism/optimism/op-program/preimage"
opservice "github.com/ethereum-optimism/optimism/op-service" opservice "github.com/ethereum-optimism/optimism/op-service"
opclient "github.com/ethereum-optimism/optimism/op-service/client" opclient "github.com/ethereum-optimism/optimism/op-service/client"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
...@@ -192,28 +192,25 @@ func PreimageServer(ctx context.Context, logger log.Logger, cfg *config.Config, ...@@ -192,28 +192,25 @@ func PreimageServer(ctx context.Context, logger log.Logger, cfg *config.Config,
func makePrefetcher(ctx context.Context, logger log.Logger, kv kvstore.KV, cfg *config.Config) (*prefetcher.Prefetcher, error) { func makePrefetcher(ctx context.Context, logger log.Logger, kv kvstore.KV, cfg *config.Config) (*prefetcher.Prefetcher, error) {
logger.Info("Connecting to L1 node", "l1", cfg.L1URL) logger.Info("Connecting to L1 node", "l1", cfg.L1URL)
l1RPC, err := client.NewRPC(ctx, logger, cfg.L1URL) l1RPC, err := createRetryingRPC(ctx, logger, cfg.L1URL)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to setup L1 RPC: %w", err) return nil, fmt.Errorf("failed to setup L1 RPC: %w", err)
} }
logger.Info("Connecting to L2 node", "l2", cfg.L2URL) logger.Info("Connecting to L2 node", "l2", cfg.L2URL)
l2RPC, err := client.NewRPC(ctx, logger, cfg.L2URL) l2RPC, err := createRetryingRPC(ctx, logger, cfg.L2URL)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to setup L2 RPC: %w", err) return nil, fmt.Errorf("failed to setup L2 RPC: %w", err)
} }
l1Backoff := opclient.NewRetryingClient(l1RPC, maxRPCRetries)
l2Backoff := opclient.NewRetryingClient(l2RPC, maxRPCRetries)
l1ClCfg := sources.L1ClientDefaultConfig(cfg.Rollup, cfg.L1TrustRPC, cfg.L1RPCKind) l1ClCfg := sources.L1ClientDefaultConfig(cfg.Rollup, cfg.L1TrustRPC, cfg.L1RPCKind)
l1Cl, err := sources.NewL1Client(l1Backoff, logger, nil, l1ClCfg) l1Cl, err := sources.NewL1Client(l1RPC, logger, nil, l1ClCfg)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create L1 client: %w", err) return nil, fmt.Errorf("failed to create L1 client: %w", err)
} }
l2ClCfg := sources.L2ClientDefaultConfig(cfg.Rollup, true) l2ClCfg := sources.L2ClientDefaultConfig(cfg.Rollup, true)
l2Cl, err := sources.NewL2Client(l2Backoff, logger, nil, l2ClCfg) l2Cl, err := sources.NewL2Client(l2RPC, logger, nil, l2ClCfg)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create L2 client: %w", err) return nil, fmt.Errorf("failed to create L2 client: %w", err)
} }
...@@ -222,6 +219,14 @@ func makePrefetcher(ctx context.Context, logger log.Logger, kv kvstore.KV, cfg * ...@@ -222,6 +219,14 @@ func makePrefetcher(ctx context.Context, logger log.Logger, kv kvstore.KV, cfg *
return prefetcher.NewPrefetcher(logger, l1Cl, l2DebugCl, kv), nil return prefetcher.NewPrefetcher(logger, l1Cl, l2DebugCl, kv), nil
} }
func createRetryingRPC(ctx context.Context, logger log.Logger, url string) (client.RPC, error) {
rpc, err := client.NewRPC(ctx, logger, url)
if err != nil {
return nil, err
}
return opclient.NewRetryingClient(logger, rpc, maxRPCRetries), nil
}
func routeHints(logger log.Logger, hHostRW io.ReadWriter, hinter preimage.HintHandler) chan error { func routeHints(logger log.Logger, hHostRW io.ReadWriter, hinter preimage.HintHandler) chan error {
chErr := make(chan error) chErr := make(chan error)
hintReader := preimage.NewHintReader(hHostRW) hintReader := preimage.NewHintReader(hHostRW)
......
...@@ -8,12 +8,12 @@ import ( ...@@ -8,12 +8,12 @@ import (
"github.com/ethereum-optimism/optimism/op-node/chaincfg" "github.com/ethereum-optimism/optimism/op-node/chaincfg"
"github.com/ethereum-optimism/optimism/op-node/testlog" "github.com/ethereum-optimism/optimism/op-node/testlog"
preimage "github.com/ethereum-optimism/optimism/op-preimage"
"github.com/ethereum-optimism/optimism/op-program/client" "github.com/ethereum-optimism/optimism/op-program/client"
"github.com/ethereum-optimism/optimism/op-program/client/l1" "github.com/ethereum-optimism/optimism/op-program/client/l1"
"github.com/ethereum-optimism/optimism/op-program/host/config" "github.com/ethereum-optimism/optimism/op-program/host/config"
"github.com/ethereum-optimism/optimism/op-program/host/kvstore" "github.com/ethereum-optimism/optimism/op-program/host/kvstore"
"github.com/ethereum-optimism/optimism/op-program/io" "github.com/ethereum-optimism/optimism/op-program/io"
"github.com/ethereum-optimism/optimism/op-program/preimage"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
......
...@@ -27,7 +27,7 @@ var ( ...@@ -27,7 +27,7 @@ var (
) )
func (s *LocalPreimageSource) Get(key common.Hash) ([]byte, error) { func (s *LocalPreimageSource) Get(key common.Hash) ([]byte, error) {
switch key { switch [32]byte(key) {
case l1HeadKey: case l1HeadKey:
return s.config.L1Head.Bytes(), nil return s.config.L1Head.Bytes(), nil
case l2HeadKey: case l2HeadKey:
......
...@@ -6,8 +6,8 @@ import ( ...@@ -6,8 +6,8 @@ import (
"testing" "testing"
"github.com/ethereum-optimism/optimism/op-node/chaincfg" "github.com/ethereum-optimism/optimism/op-node/chaincfg"
preimage "github.com/ethereum-optimism/optimism/op-preimage"
"github.com/ethereum-optimism/optimism/op-program/host/config" "github.com/ethereum-optimism/optimism/op-program/host/config"
"github.com/ethereum-optimism/optimism/op-program/preimage"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
......
package kvstore package kvstore
import ( import (
"github.com/ethereum-optimism/optimism/op-program/preimage" preimage "github.com/ethereum-optimism/optimism/op-preimage"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
...@@ -19,7 +19,7 @@ func NewPreimageSourceSplitter(local PreimageSource, global PreimageSource) *Pre ...@@ -19,7 +19,7 @@ func NewPreimageSourceSplitter(local PreimageSource, global PreimageSource) *Pre
} }
} }
func (s *PreimageSourceSplitter) Get(key common.Hash) ([]byte, error) { func (s *PreimageSourceSplitter) Get(key [32]byte) ([]byte, error) {
if key[0] == byte(preimage.LocalKeyType) { if key[0] == byte(preimage.LocalKeyType) {
return s.local(key) return s.local(key)
} }
......
...@@ -3,7 +3,7 @@ package kvstore ...@@ -3,7 +3,7 @@ package kvstore
import ( import (
"testing" "testing"
"github.com/ethereum-optimism/optimism/op-program/preimage" preimage "github.com/ethereum-optimism/optimism/op-preimage"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
......
...@@ -7,11 +7,11 @@ import ( ...@@ -7,11 +7,11 @@ import (
"strings" "strings"
"github.com/ethereum-optimism/optimism/op-node/eth" "github.com/ethereum-optimism/optimism/op-node/eth"
preimage "github.com/ethereum-optimism/optimism/op-preimage"
"github.com/ethereum-optimism/optimism/op-program/client/l1" "github.com/ethereum-optimism/optimism/op-program/client/l1"
"github.com/ethereum-optimism/optimism/op-program/client/l2" "github.com/ethereum-optimism/optimism/op-program/client/l2"
"github.com/ethereum-optimism/optimism/op-program/client/mpt" "github.com/ethereum-optimism/optimism/op-program/client/mpt"
"github.com/ethereum-optimism/optimism/op-program/host/kvstore" "github.com/ethereum-optimism/optimism/op-program/host/kvstore"
"github.com/ethereum-optimism/optimism/op-program/preimage"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
......
...@@ -15,11 +15,11 @@ import ( ...@@ -15,11 +15,11 @@ import (
"github.com/ethereum-optimism/optimism/op-node/eth" "github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/testutils" "github.com/ethereum-optimism/optimism/op-node/testutils"
preimage "github.com/ethereum-optimism/optimism/op-preimage"
"github.com/ethereum-optimism/optimism/op-program/client/l1" "github.com/ethereum-optimism/optimism/op-program/client/l1"
"github.com/ethereum-optimism/optimism/op-program/client/l2" "github.com/ethereum-optimism/optimism/op-program/client/l2"
"github.com/ethereum-optimism/optimism/op-program/client/mpt" "github.com/ethereum-optimism/optimism/op-program/client/mpt"
"github.com/ethereum-optimism/optimism/op-program/host/kvstore" "github.com/ethereum-optimism/optimism/op-program/host/kvstore"
"github.com/ethereum-optimism/optimism/op-program/preimage"
) )
func TestNoHint(t *testing.T) { func TestNoHint(t *testing.T) {
......
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
...@@ -19,6 +20,7 @@ var ( ...@@ -19,6 +20,7 @@ var (
// retryingClient wraps a [client.RPC] with a backoff strategy. // retryingClient wraps a [client.RPC] with a backoff strategy.
type retryingClient struct { type retryingClient struct {
log log.Logger
c client.RPC c client.RPC
retryAttempts int retryAttempts int
strategy backoff.Strategy strategy backoff.Strategy
...@@ -26,11 +28,12 @@ type retryingClient struct { ...@@ -26,11 +28,12 @@ type retryingClient struct {
// NewRetryingClient creates a new retrying client. // NewRetryingClient creates a new retrying client.
// The backoff strategy is optional, if not provided, the default exponential backoff strategy is used. // The backoff strategy is optional, if not provided, the default exponential backoff strategy is used.
func NewRetryingClient(c client.RPC, retries int, strategy ...backoff.Strategy) *retryingClient { func NewRetryingClient(logger log.Logger, c client.RPC, retries int, strategy ...backoff.Strategy) *retryingClient {
if len(strategy) == 0 { if len(strategy) == 0 {
strategy = []backoff.Strategy{ExponentialBackoff} strategy = []backoff.Strategy{ExponentialBackoff}
} }
return &retryingClient{ return &retryingClient{
log: logger,
c: c, c: c,
retryAttempts: retries, retryAttempts: retries,
strategy: strategy[0], strategy: strategy[0],
...@@ -50,7 +53,11 @@ func (b *retryingClient) CallContext(ctx context.Context, result any, method str ...@@ -50,7 +53,11 @@ func (b *retryingClient) CallContext(ctx context.Context, result any, method str
return backoff.DoCtx(ctx, b.retryAttempts, b.strategy, func() error { return backoff.DoCtx(ctx, b.retryAttempts, b.strategy, func() error {
cCtx, cancel := context.WithTimeout(ctx, 10*time.Second) cCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel() defer cancel()
return b.c.CallContext(cCtx, result, method, args...) err := b.c.CallContext(cCtx, result, method, args...)
if err != nil {
b.log.Warn("RPC request failed", "method", method, "err", err)
}
return err
}) })
} }
...@@ -85,6 +92,7 @@ func (b *retryingClient) BatchCallContext(ctx context.Context, input []rpc.Batch ...@@ -85,6 +92,7 @@ func (b *retryingClient) BatchCallContext(ctx context.Context, input []rpc.Batch
} }
err := b.c.BatchCallContext(cCtx, batch) err := b.c.BatchCallContext(cCtx, batch)
if err != nil { if err != nil {
b.log.Warn("Batch request failed", "err", err)
// Whole call failed, retry all pending elems again // Whole call failed, retry all pending elems again
return err return err
} }
...@@ -107,6 +115,7 @@ func (b *retryingClient) BatchCallContext(ctx context.Context, input []rpc.Batch ...@@ -107,6 +115,7 @@ func (b *retryingClient) BatchCallContext(ctx context.Context, input []rpc.Batch
} }
if len(failed) > 0 { if len(failed) > 0 {
pending = failed pending = failed
b.log.Warn("Batch request returned errors", "err", combinedErr)
return combinedErr return combinedErr
} }
return nil return nil
...@@ -118,6 +127,9 @@ func (b *retryingClient) EthSubscribe(ctx context.Context, channel any, args ... ...@@ -118,6 +127,9 @@ func (b *retryingClient) EthSubscribe(ctx context.Context, channel any, args ...
err := backoff.DoCtx(ctx, b.retryAttempts, b.strategy, func() error { err := backoff.DoCtx(ctx, b.retryAttempts, b.strategy, func() error {
var err error var err error
sub, err = b.c.EthSubscribe(ctx, channel, args...) sub, err = b.c.EthSubscribe(ctx, channel, args...)
if err != nil {
b.log.Warn("Subscription request failed", "err", err)
}
return err return err
}) })
return sub, err return sub, err
......
...@@ -5,6 +5,8 @@ import ( ...@@ -5,6 +5,8 @@ import (
"errors" "errors"
"testing" "testing"
"github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/mock" "github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
...@@ -66,18 +68,18 @@ var _ opclient.RPC = (*MockRPC)(nil) ...@@ -66,18 +68,18 @@ var _ opclient.RPC = (*MockRPC)(nil)
func TestClient_BackoffClient_Strategy(t *testing.T) { func TestClient_BackoffClient_Strategy(t *testing.T) {
mockRpc := &MockRPC{} mockRpc := &MockRPC{}
backoffClient := client.NewRetryingClient(mockRpc, 0) backoffClient := client.NewRetryingClient(testlog.Logger(t, log.LvlInfo), mockRpc, 0)
require.Equal(t, backoffClient.BackoffStrategy(), client.ExponentialBackoff) require.Equal(t, backoffClient.BackoffStrategy(), client.ExponentialBackoff)
fixedStrategy := &backoff.FixedStrategy{} fixedStrategy := &backoff.FixedStrategy{}
backoffClient = client.NewRetryingClient(mockRpc, 0, fixedStrategy) backoffClient = client.NewRetryingClient(testlog.Logger(t, log.LvlInfo), mockRpc, 0, fixedStrategy)
require.Equal(t, backoffClient.BackoffStrategy(), fixedStrategy) require.Equal(t, backoffClient.BackoffStrategy(), fixedStrategy)
} }
func TestClient_BackoffClient_Close(t *testing.T) { func TestClient_BackoffClient_Close(t *testing.T) {
mockRpc := &MockRPC{} mockRpc := &MockRPC{}
mockRpc.On("Close").Return() mockRpc.On("Close").Return()
backoffClient := client.NewRetryingClient(mockRpc, 0) backoffClient := client.NewRetryingClient(testlog.Logger(t, log.LvlInfo), mockRpc, 0)
backoffClient.Close() backoffClient.Close()
require.True(t, mockRpc.AssertCalled(t, "Close")) require.True(t, mockRpc.AssertCalled(t, "Close"))
} }
...@@ -85,7 +87,7 @@ func TestClient_BackoffClient_Close(t *testing.T) { ...@@ -85,7 +87,7 @@ func TestClient_BackoffClient_Close(t *testing.T) {
func TestClient_BackoffClient_CallContext(t *testing.T) { func TestClient_BackoffClient_CallContext(t *testing.T) {
mockRpc := &MockRPC{} mockRpc := &MockRPC{}
mockRpc.ExpectCallContext(nil, nil, "foo", "bar") mockRpc.ExpectCallContext(nil, nil, "foo", "bar")
backoffClient := client.NewRetryingClient(mockRpc, 1) backoffClient := client.NewRetryingClient(testlog.Logger(t, log.LvlInfo), mockRpc, 1)
err := backoffClient.CallContext(context.Background(), nil, "foo", "bar") err := backoffClient.CallContext(context.Background(), nil, "foo", "bar")
require.NoError(t, err) require.NoError(t, err)
require.True(t, mockRpc.AssertCalled(t, "CallContext", mock.Anything, nil, "foo", []interface{}{"bar"})) require.True(t, mockRpc.AssertCalled(t, "CallContext", mock.Anything, nil, "foo", []interface{}{"bar"}))
...@@ -94,7 +96,7 @@ func TestClient_BackoffClient_CallContext(t *testing.T) { ...@@ -94,7 +96,7 @@ func TestClient_BackoffClient_CallContext(t *testing.T) {
func TestClient_BackoffClient_CallContext_WithRetries(t *testing.T) { func TestClient_BackoffClient_CallContext_WithRetries(t *testing.T) {
mockRpc := &MockRPC{} mockRpc := &MockRPC{}
mockRpc.ExpectCallContext(errors.New("foo"), nil, "foo", "bar") mockRpc.ExpectCallContext(errors.New("foo"), nil, "foo", "bar")
backoffClient := client.NewRetryingClient(mockRpc, 2, backoff.Fixed(0)) backoffClient := client.NewRetryingClient(testlog.Logger(t, log.LvlInfo), mockRpc, 2, backoff.Fixed(0))
err := backoffClient.CallContext(context.Background(), nil, "foo", "bar") err := backoffClient.CallContext(context.Background(), nil, "foo", "bar")
require.Error(t, err) require.Error(t, err)
require.True(t, mockRpc.AssertNumberOfCalls(t, "CallContext", 2)) require.True(t, mockRpc.AssertNumberOfCalls(t, "CallContext", 2))
...@@ -103,7 +105,7 @@ func TestClient_BackoffClient_CallContext_WithRetries(t *testing.T) { ...@@ -103,7 +105,7 @@ func TestClient_BackoffClient_CallContext_WithRetries(t *testing.T) {
func TestClient_BackoffClient_BatchCallContext(t *testing.T) { func TestClient_BackoffClient_BatchCallContext(t *testing.T) {
mockRpc := &MockRPC{} mockRpc := &MockRPC{}
mockRpc.ExpectBatchCallContext(nil, []rpc.BatchElem{}) mockRpc.ExpectBatchCallContext(nil, []rpc.BatchElem{})
backoffClient := client.NewRetryingClient(mockRpc, 1) backoffClient := client.NewRetryingClient(testlog.Logger(t, log.LvlInfo), mockRpc, 1)
err := backoffClient.BatchCallContext(context.Background(), nil) err := backoffClient.BatchCallContext(context.Background(), nil)
require.NoError(t, err) require.NoError(t, err)
require.True(t, mockRpc.AssertCalled(t, "BatchCallContext", mock.Anything, []rpc.BatchElem{})) require.True(t, mockRpc.AssertCalled(t, "BatchCallContext", mock.Anything, []rpc.BatchElem{}))
...@@ -112,7 +114,7 @@ func TestClient_BackoffClient_BatchCallContext(t *testing.T) { ...@@ -112,7 +114,7 @@ func TestClient_BackoffClient_BatchCallContext(t *testing.T) {
func TestClient_BackoffClient_BatchCallContext_WithRetries(t *testing.T) { func TestClient_BackoffClient_BatchCallContext_WithRetries(t *testing.T) {
mockRpc := &MockRPC{} mockRpc := &MockRPC{}
mockRpc.ExpectBatchCallContext(errors.New("foo"), []rpc.BatchElem{}) mockRpc.ExpectBatchCallContext(errors.New("foo"), []rpc.BatchElem{})
backoffClient := client.NewRetryingClient(mockRpc, 2, backoff.Fixed(0)) backoffClient := client.NewRetryingClient(testlog.Logger(t, log.LvlInfo), mockRpc, 2, backoff.Fixed(0))
err := backoffClient.BatchCallContext(context.Background(), nil) err := backoffClient.BatchCallContext(context.Background(), nil)
require.Error(t, err) require.Error(t, err)
require.True(t, mockRpc.AssertNumberOfCalls(t, "BatchCallContext", 2)) require.True(t, mockRpc.AssertNumberOfCalls(t, "BatchCallContext", 2))
...@@ -134,7 +136,7 @@ func TestClient_BackoffClient_BatchCallContext_WithPartialRetries(t *testing.T) ...@@ -134,7 +136,7 @@ func TestClient_BackoffClient_BatchCallContext_WithPartialRetries(t *testing.T)
batch[0].Error = errors.New("boom again") batch[0].Error = errors.New("boom again")
batch[1].Result = batch[1].Method batch[1].Result = batch[1].Method
}) })
backoffClient := client.NewRetryingClient(mockRpc, 2, backoff.Fixed(0)) backoffClient := client.NewRetryingClient(testlog.Logger(t, log.LvlInfo), mockRpc, 2, backoff.Fixed(0))
err := backoffClient.BatchCallContext(context.Background(), batches) err := backoffClient.BatchCallContext(context.Background(), batches)
require.Error(t, err) require.Error(t, err)
require.True(t, mockRpc.AssertNumberOfCalls(t, "BatchCallContext", 2)) require.True(t, mockRpc.AssertNumberOfCalls(t, "BatchCallContext", 2))
...@@ -164,7 +166,7 @@ func TestClient_BackoffClient_BatchCallContext_WithPartialRetriesUntilSuccess(t ...@@ -164,7 +166,7 @@ func TestClient_BackoffClient_BatchCallContext_WithPartialRetriesUntilSuccess(t
mockRpc.OnBatchCallContext(nil, []rpc.BatchElem{batches[1]}, func(batch []rpc.BatchElem) { mockRpc.OnBatchCallContext(nil, []rpc.BatchElem{batches[1]}, func(batch []rpc.BatchElem) {
batch[0].Result = batch[0].Method batch[0].Result = batch[0].Method
}) })
backoffClient := client.NewRetryingClient(mockRpc, 4, backoff.Fixed(0)) backoffClient := client.NewRetryingClient(testlog.Logger(t, log.LvlInfo), mockRpc, 4, backoff.Fixed(0))
err := backoffClient.BatchCallContext(context.Background(), batches) err := backoffClient.BatchCallContext(context.Background(), batches)
require.NoError(t, err) require.NoError(t, err)
require.True(t, mockRpc.AssertNumberOfCalls(t, "BatchCallContext", 3)) require.True(t, mockRpc.AssertNumberOfCalls(t, "BatchCallContext", 3))
...@@ -178,7 +180,7 @@ func TestClient_BackoffClient_BatchCallContext_WithPartialRetriesUntilSuccess(t ...@@ -178,7 +180,7 @@ func TestClient_BackoffClient_BatchCallContext_WithPartialRetriesUntilSuccess(t
func TestClient_BackoffClient_EthSubscribe(t *testing.T) { func TestClient_BackoffClient_EthSubscribe(t *testing.T) {
mockRpc := &MockRPC{} mockRpc := &MockRPC{}
mockRpc.ExpectEthSubscribe(ethereum.Subscription(nil), nil, nil, "foo", "bar") mockRpc.ExpectEthSubscribe(ethereum.Subscription(nil), nil, nil, "foo", "bar")
backoffClient := client.NewRetryingClient(mockRpc, 1) backoffClient := client.NewRetryingClient(testlog.Logger(t, log.LvlInfo), mockRpc, 1)
_, err := backoffClient.EthSubscribe(context.Background(), nil, "foo", "bar") _, err := backoffClient.EthSubscribe(context.Background(), nil, "foo", "bar")
require.NoError(t, err) require.NoError(t, err)
require.True(t, mockRpc.AssertCalled(t, "EthSubscribe", mock.Anything, nil, []interface{}{"foo", "bar"})) require.True(t, mockRpc.AssertCalled(t, "EthSubscribe", mock.Anything, nil, []interface{}{"foo", "bar"}))
...@@ -187,7 +189,7 @@ func TestClient_BackoffClient_EthSubscribe(t *testing.T) { ...@@ -187,7 +189,7 @@ func TestClient_BackoffClient_EthSubscribe(t *testing.T) {
func TestClient_BackoffClient_EthSubscribe_WithRetries(t *testing.T) { func TestClient_BackoffClient_EthSubscribe_WithRetries(t *testing.T) {
mockRpc := &MockRPC{} mockRpc := &MockRPC{}
mockRpc.ExpectEthSubscribe(ethereum.Subscription(nil), errors.New("foo"), nil, "foo", "bar") mockRpc.ExpectEthSubscribe(ethereum.Subscription(nil), errors.New("foo"), nil, "foo", "bar")
backoffClient := client.NewRetryingClient(mockRpc, 2, backoff.Fixed(0)) backoffClient := client.NewRetryingClient(testlog.Logger(t, log.LvlInfo), mockRpc, 2, backoff.Fixed(0))
_, err := backoffClient.EthSubscribe(context.Background(), nil, "foo", "bar") _, err := backoffClient.EthSubscribe(context.Background(), nil, "foo", "bar")
require.Error(t, err) require.Error(t, err)
require.True(t, mockRpc.AssertNumberOfCalls(t, "EthSubscribe", 2)) require.True(t, mockRpc.AssertNumberOfCalls(t, "EthSubscribe", 2))
......
...@@ -39,7 +39,6 @@ COPY --from=foundry-build /opt/foundry/target/release/cast /usr/local/bin/cast ...@@ -39,7 +39,6 @@ COPY --from=foundry-build /opt/foundry/target/release/cast /usr/local/bin/cast
COPY --from=foundry-build /opt/foundry/target/release/anvil /usr/local/bin/anvil COPY --from=foundry-build /opt/foundry/target/release/anvil /usr/local/bin/anvil
COPY --from=geth /usr/local/bin/abigen /usr/local/bin/abigen COPY --from=geth /usr/local/bin/abigen /usr/local/bin/abigen
COPY --from=echidna-test /usr/local/bin/echidna-test /usr/local/bin/echidna-test COPY --from=echidna-test /usr/local/bin/echidna-test /usr/local/bin/echidna-test
COPY check-changed.sh /usr/local/bin/check-changed
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y bash curl openssh-client git build-essential ca-certificates jq musl gnupg coreutils && \ apt-get install -y bash curl openssh-client git build-essential ca-certificates jq musl gnupg coreutils && \
...@@ -55,8 +54,7 @@ RUN apt-get update && \ ...@@ -55,8 +54,7 @@ RUN apt-get update && \
pip install slither-analyzer==0.9.3 && \ pip install slither-analyzer==0.9.3 && \
go install gotest.tools/gotestsum@latest && \ go install gotest.tools/gotestsum@latest && \
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.48.0 && \ curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.48.0 && \
curl -fLSs https://raw.githubusercontent.com/CircleCI-Public/circleci-cli/master/install.sh | bash && \ curl -fLSs https://raw.githubusercontent.com/CircleCI-Public/circleci-cli/master/install.sh | bash
chmod +x /usr/local/bin/check-changed
RUN echo "downloading solidity compilers" && \ RUN echo "downloading solidity compilers" && \
curl -o solc-linux-amd64-v0.5.17+commit.d19bba13 -sL https://binaries.soliditylang.org/linux-amd64/solc-linux-amd64-v0.5.17+commit.d19bba13 && \ curl -o solc-linux-amd64-v0.5.17+commit.d19bba13 -sL https://binaries.soliditylang.org/linux-amd64/solc-linux-amd64-v0.5.17+commit.d19bba13 && \
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
# @eth-optimism/drippie-mon # @eth-optimism/drippie-mon
## 0.4.0
### Minor Changes
- d6388be4a: Added a new service wallet-mon to identify unexpected transfers from key accounts
### Patch Changes
- 287d317d3: Fixed an issue with logging the wrong timestamp.
- Updated dependencies [8d7dcc70c]
- Updated dependencies [119754c2f]
- Updated dependencies [d6388be4a]
- Updated dependencies [af292562f]
- @eth-optimism/core-utils@0.12.1
- @eth-optimism/sdk@3.0.0
- @eth-optimism/contracts-bedrock@0.15.0
- @eth-optimism/common-ts@0.8.2
## 0.3.1 ## 0.3.1
### Patch Changes ### Patch Changes
......
{ {
"private": true, "private": true,
"name": "@eth-optimism/chain-mon", "name": "@eth-optimism/chain-mon",
"version": "0.3.1", "version": "0.4.0",
"description": "[Optimism] Chain monitoring services", "description": "[Optimism] Chain monitoring services",
"main": "dist/index", "main": "dist/index",
"types": "dist/index", "types": "dist/index",
...@@ -34,11 +34,11 @@ ...@@ -34,11 +34,11 @@
"url": "https://github.com/ethereum-optimism/optimism.git" "url": "https://github.com/ethereum-optimism/optimism.git"
}, },
"dependencies": { "dependencies": {
"@eth-optimism/common-ts": "0.8.1", "@eth-optimism/common-ts": "0.8.2",
"@eth-optimism/contracts-periphery": "1.0.8", "@eth-optimism/contracts-periphery": "1.0.8",
"@eth-optimism/contracts-bedrock": "0.14.0", "@eth-optimism/contracts-bedrock": "0.15.0",
"@eth-optimism/core-utils": "0.12.0", "@eth-optimism/core-utils": "0.12.1",
"@eth-optimism/sdk": "2.1.0", "@eth-optimism/sdk": "3.0.0",
"ethers": "^5.7.0", "ethers": "^5.7.0",
"@types/dateformat": "^5.0.0", "@types/dateformat": "^5.0.0",
"chai-as-promised": "^7.1.1", "chai-as-promised": "^7.1.1",
......
# @eth-optimism/common-ts # @eth-optimism/common-ts
## 0.8.2
### Patch Changes
- Updated dependencies [8d7dcc70c]
- Updated dependencies [d6388be4a]
- @eth-optimism/core-utils@0.12.1
## 0.8.1 ## 0.8.1
### Patch Changes ### Patch Changes
......
{ {
"name": "@eth-optimism/common-ts", "name": "@eth-optimism/common-ts",
"version": "0.8.1", "version": "0.8.2",
"description": "[Optimism] Advanced typescript tooling used by various services", "description": "[Optimism] Advanced typescript tooling used by various services",
"main": "dist/index", "main": "dist/index",
"types": "dist/index", "types": "dist/index",
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
"url": "https://github.com/ethereum-optimism/optimism.git" "url": "https://github.com/ethereum-optimism/optimism.git"
}, },
"dependencies": { "dependencies": {
"@eth-optimism/core-utils": "0.12.0", "@eth-optimism/core-utils": "0.12.1",
"@sentry/node": "^6.3.1", "@sentry/node": "^6.3.1",
"bcfg": "^0.1.7", "bcfg": "^0.1.7",
"body-parser": "^1.20.0", "body-parser": "^1.20.0",
......
...@@ -32,19 +32,24 @@ DisputeGameFactory_SetImplementation_Test:test_setImplementation_notOwner_revert ...@@ -32,19 +32,24 @@ DisputeGameFactory_SetImplementation_Test:test_setImplementation_notOwner_revert
DisputeGameFactory_SetImplementation_Test:test_setImplementation_succeeds() (gas: 44243) DisputeGameFactory_SetImplementation_Test:test_setImplementation_succeeds() (gas: 44243)
DisputeGameFactory_TransferOwnership_Test:test_transferOwnership_notOwner_reverts() (gas: 15950) DisputeGameFactory_TransferOwnership_Test:test_transferOwnership_notOwner_reverts() (gas: 15950)
DisputeGameFactory_TransferOwnership_Test:test_transferOwnership_succeeds() (gas: 18642) DisputeGameFactory_TransferOwnership_Test:test_transferOwnership_succeeds() (gas: 18642)
FaultDisputeGame_Test:test_clockTimeExceeded_reverts() (gas: 26468) FaultDisputeGame_Test:test_clockTimeExceeded_reverts() (gas: 26496)
FaultDisputeGame_Test:test_defendRoot_reverts() (gas: 13258) FaultDisputeGame_Test:test_defendRoot_reverts() (gas: 13236)
FaultDisputeGame_Test:test_duplicateClaim_reverts() (gas: 103369) FaultDisputeGame_Test:test_duplicateClaim_reverts() (gas: 103425)
FaultDisputeGame_Test:test_extraData_succeeds() (gas: 17478) FaultDisputeGame_Test:test_extraData_succeeds() (gas: 17478)
FaultDisputeGame_Test:test_gameData_succeeds() (gas: 17859) FaultDisputeGame_Test:test_gameData_succeeds() (gas: 17859)
FaultDisputeGame_Test:test_gameDepthExceeded_reverts() (gas: 5906891) FaultDisputeGame_Test:test_gameDepthExceeded_reverts() (gas: 5907231)
FaultDisputeGame_Test:test_gameStart_succeeds() (gas: 10337) FaultDisputeGame_Test:test_gameStart_succeeds() (gas: 10337)
FaultDisputeGame_Test:test_gameType_succeeds() (gas: 8194) FaultDisputeGame_Test:test_gameType_succeeds() (gas: 8259)
FaultDisputeGame_Test:test_initialRootClaimData_succeeds() (gas: 17580) FaultDisputeGame_Test:test_initialRootClaimData_succeeds() (gas: 17624)
FaultDisputeGame_Test:test_moveAgainstNonexistentParent_reverts() (gas: 24587) FaultDisputeGame_Test:test_moveAgainstNonexistentParent_reverts() (gas: 24632)
FaultDisputeGame_Test:test_move_gameNotInProgress_reverts() (gas: 10945) FaultDisputeGame_Test:test_move_gameNotInProgress_reverts() (gas: 10945)
FaultDisputeGame_Test:test_rootClaim_succeeds() (gas: 8191) FaultDisputeGame_Test:test_resolve_challengeContested() (gas: 222383)
FaultDisputeGame_Test:test_simpleAttack_succeeds() (gas: 107361) FaultDisputeGame_Test:test_resolve_reverts() (gas: 27121)
FaultDisputeGame_Test:test_resolve_rootContested() (gas: 107225)
FaultDisputeGame_Test:test_resolve_rootUncontested() (gas: 24459)
FaultDisputeGame_Test:test_resolve_teamDeathmatch() (gas: 393609)
FaultDisputeGame_Test:test_rootClaim_succeeds() (gas: 8169)
FaultDisputeGame_Test:test_simpleAttack_succeeds() (gas: 107389)
FaultDisputeGame_Test:test_version_succeeds() (gas: 9780) FaultDisputeGame_Test:test_version_succeeds() (gas: 9780)
FeeVault_Test:test_constructor_succeeds() (gas: 18185) FeeVault_Test:test_constructor_succeeds() (gas: 18185)
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 352135) GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 352135)
......
...@@ -14,3 +14,7 @@ deployments ...@@ -14,3 +14,7 @@ deployments
# Other autogenerated files # Other autogenerated files
gasReporterOutput.json gasReporterOutput.json
slither.db.json slither.db.json
# MIPS.sol has special VM formatting, not like other contracts.
# Prettier also fails to handle YUL functions with multiple return variables.
contracts/cannon/MIPS.sol
...@@ -3,3 +3,6 @@ node_modules ...@@ -3,3 +3,6 @@ node_modules
lib lib
contracts/test/*.t.sol contracts/test/*.t.sol
contracts/vendor/*.sol contracts/vendor/*.sol
# MIPS.sol has special VM formatting, not like other contracts.
contracts/cannon/MIPS.sol
# @eth-optimism/contracts-bedrock # @eth-optimism/contracts-bedrock
## 0.15.0
### Minor Changes
- af292562f: Fix issue with deposits running out of gas
### Patch Changes
- Updated dependencies [8d7dcc70c]
- Updated dependencies [d6388be4a]
- @eth-optimism/core-utils@0.12.1
## 0.14.0 ## 0.14.0
### Minor Changes ### Minor Changes
......
// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
interface IPreimageOracle {
function readPreimage(bytes32 key, uint256 offset) external view returns (bytes32 dat, uint256 datLen);
}
// https://inst.eecs.berkeley.edu/~cs61c/resources/MIPS_Green_Sheet.pdf
// https://uweb.engr.arizona.edu/~ece369/Resources/spim/MIPSReference.pdf
// https://en.wikibooks.org/wiki/MIPS_Assembly/Instruction_Formats
// https://www.cs.cmu.edu/afs/cs/academic/class/15740-f97/public/doc/mips-isa.pdf
// page A-177
// MIPS linux kernel errors used by Go runtime:
// https://github.com/golang/go/blob/master/src/syscall/zerrors_linux_mips.go
// This MIPS contract emulates a single MIPS instruction.
//
// Note that delay slots are isolated instructions:
// the nextPC in the state pre-schedules where the VM jumps next.
//
// The Step input is a packed VM state, with binary-merkle-tree witness data for memory reads/writes.
// The Step outputs a keccak256 hash of the packed VM State, and logs the resulting state for offchain usage.
contract MIPS {
struct State {
bytes32 memRoot;
bytes32 preimageKey;
uint32 preimageOffset;
uint32 pc;
uint32 nextPC; // State is executing a branch/jump delay slot if nextPC != pc+4
uint32 lo;
uint32 hi;
uint32 heap;
uint8 exitCode;
bool exited;
uint64 step;
uint32[32] registers;
}
// total State size: 32+32+6*4+1+1+8+32*4 = 226 bytes
uint32 constant public BRK_START = 0x40000000;
uint32 constant FD_STDIN = 0;
uint32 constant FD_STDOUT = 1;
uint32 constant FD_STDERR = 2;
uint32 constant FD_HINT_READ = 3;
uint32 constant FD_HINT_WRITE = 4;
uint32 constant FD_PREIMAGE_READ = 5;
uint32 constant FD_PREIMAGE_WRITE = 6;
uint32 constant EBADF = 0x9;
uint32 constant EINVAL = 0x16;
IPreimageOracle public oracle;
function SE(uint32 dat, uint32 idx) internal pure returns (uint32) {
bool isSigned = (dat >> (idx-1)) != 0;
uint256 signed = ((1 << (32-idx)) - 1) << idx;
uint256 mask = (1 << idx) - 1;
return uint32(dat&mask | (isSigned ? signed : 0));
}
function outputState() internal returns (bytes32 out) {
assembly {
// copies 'size' bytes, right-aligned in word at 'from', to 'to', incl. trailing data
function copyMem(from, to, size) -> fromOut, toOut {
mstore(to, mload(add(from, sub(32, size))))
fromOut := add(from, 32)
toOut := add(to, size)
}
let from := 0x80 // state
let start := mload(0x40) // free mem ptr
let to := start
from, to := copyMem(from, to, 32) // memRoot
from, to := copyMem(from, to, 32) // preimageKey
from, to := copyMem(from, to, 4) // preimageOffset
from, to := copyMem(from, to, 4) // pc
from, to := copyMem(from, to, 4) // nextPC
from, to := copyMem(from, to, 4) // lo
from, to := copyMem(from, to, 4) // hi
from, to := copyMem(from, to, 4) // heap
from, to := copyMem(from, to, 1) // exitCode
from, to := copyMem(from, to, 1) // exited
from, to := copyMem(from, to, 8) // step
from := add(from, 32) // offset to registers
for { let i := 0 } lt(i, 32) { i := add(i, 1) } { from, to := copyMem(from, to, 4) } // registers
mstore(to, 0) // clean up end
log0(start, sub(to, start)) // log the resulting MIPS state, for debugging
out := keccak256(start, sub(to, start))
}
return out;
}
function handleSyscall() internal returns (bytes32) {
State memory state;
assembly {
state := 0x80
}
uint32 syscall_no = state.registers[2];
uint32 v0 = 0;
uint32 v1 = 0;
uint32 a0 = state.registers[4];
uint32 a1 = state.registers[5];
uint32 a2 = state.registers[6];
if (syscall_no == 4090) {
// mmap
uint32 sz = a1;
if (sz&4095 != 0) { // adjust size to align with page size
sz += 4096 - (sz&4095);
}
if (a0 == 0) {
v0 = state.heap;
state.heap += sz;
} else {
v0 = a0;
}
} else if (syscall_no == 4045) {
// brk
v0 = BRK_START;
} else if (syscall_no == 4120) {
// clone (not supported)
v0 = 1;
} else if (syscall_no == 4246) {
// exit group
state.exited = true;
state.exitCode = uint8(a0);
return outputState();
} else if (syscall_no == 4003) { // read
// args: a0 = fd, a1 = addr, a2 = count
// returns: v0 = read, v1 = err code
if (a0 == FD_STDIN) {
// leave v0 and v1 zero: read nothing, no error
} else if (a0 == FD_PREIMAGE_READ) { // pre-image oracle
// verify proof 1 is correct, and get the existing memory.
uint32 mem = readMem(a1 & 0xFFffFFfc, 1); // mask the addr to align it to 4 bytes
(bytes32 dat, uint256 datLen) = oracle.readPreimage(state.preimageKey, state.preimageOffset);
assembly { // assembly for more precise ops, and no var count limit
let alignment := and(a1, 3) // the read might not start at an aligned address
let space := sub(4, alignment) // remaining space in memory word
if lt(space, datLen) { datLen := space } // if less space than data, shorten data
if lt(a2, datLen) { datLen := a2 } // if requested to read less, read less
dat := shr(sub(256, mul(datLen, 8)), dat) // right-align data
dat := shl(mul(alignment, 8), dat) // position data to insert into memory word
let mask := sub(shl(mul(sub(4, alignment), 8), 1), 1) // mask all bytes after start
let suffixMask := sub(shl(mul(add(sub(4, alignment), datLen), 8), 1), 1) // mask of all bytes starting from end, maybe none
mask := and(mask, not(suffixMask)) // reduce mask to just cover the data we insert
mem := or(and(mem, not(mask)), dat) // clear masked part of original memory, and insert data
}
writeMem(a1 & 0xFFffFFfc, 1, mem);
state.preimageOffset += uint32(datLen);
v0 = uint32(datLen);
} else if (a0 == FD_HINT_READ) { // hint response
// don't actually read into memory, just say we read it all, we ignore the result anyway
v0 = a2;
} else {
v0 = 0xFFffFFff;
v1 = EBADF;
}
} else if (syscall_no == 4004) { // write
// args: a0 = fd, a1 = addr, a2 = count
// returns: v0 = written, v1 = err code
if (a0 == FD_STDOUT || a0 == FD_STDERR || a0 == FD_HINT_WRITE) {
v0 = a2; // tell program we have written everything
} else if (a0 == FD_PREIMAGE_WRITE) { // pre-image oracle
uint32 mem = readMem(a1 & 0xFFffFFfc, 1); // mask the addr to align it to 4 bytes
bytes32 key = state.preimageKey;
assembly { // assembly for more precise ops, and no var count limit
let alignment := and(a1, 3) // the read might not start at an aligned address
let space := sub(4, alignment) // remaining space in memory word
if lt(space, a2) { a2 := space } // if less space than data, shorten data
key := shl(mul(a2, 8), key) // shift key, make space for new info
let mask := sub(shl(mul(a2, 8), 1), 1) // mask for extracting value from memory
mem := and(shr(mul(sub(space, a2), 8), mem), mask) // align value to right, mask it
key := or(key, mem) // insert into key
}
state.preimageKey = key;
state.preimageOffset = 0; // reset offset, to read new pre-image data from the start
v0 = a2;
} else {
v0 = 0xFFffFFff;
v1 = EBADF;
}
} else if (syscall_no == 4055) { // fcntl
// args: a0 = fd, a1 = cmd
if (a1 == 3) { // F_GETFL: get file descriptor flags
if (a0 == FD_STDIN || a0 == FD_PREIMAGE_READ || a0 == FD_HINT_READ) {
v0 = 0; // O_RDONLY
} else if (a0 == FD_STDOUT || a0 == FD_STDERR || a0 == FD_PREIMAGE_WRITE || a0 == FD_HINT_WRITE) {
v0 = 1; // O_WRONLY
} else {
v0 = 0xFFffFFff;
v1 = EBADF;
}
} else {
v0 = 0xFFffFFff;
v1 = EINVAL; // cmd not recognized by this kernel
}
}
state.registers[2] = v0;
state.registers[7] = v1;
state.pc = state.nextPC;
state.nextPC = state.nextPC + 4;
return outputState();
}
function handleBranch(uint32 opcode, uint32 insn, uint32 rtReg, uint32 rs) internal returns (bytes32) {
State memory state;
assembly {
state := 0x80
}
bool shouldBranch = false;
if (opcode == 4 || opcode == 5) { // beq/bne
uint32 rt = state.registers[rtReg];
shouldBranch = (rs == rt && opcode == 4) || (rs != rt && opcode == 5);
} else if (opcode == 6) { shouldBranch = int32(rs) <= 0; // blez
} else if (opcode == 7) { shouldBranch = int32(rs) > 0; // bgtz
} else if (opcode == 1) {
// regimm
uint32 rtv = ((insn >> 16) & 0x1F);
if (rtv == 0) shouldBranch = int32(rs) < 0; // bltz
if (rtv == 1) shouldBranch = int32(rs) >= 0; // bgez
}
uint32 prevPC = state.pc;
state.pc = state.nextPC; // execute the delay slot first
if (shouldBranch) {
state.nextPC = prevPC + 4 + (SE(insn&0xFFFF, 16)<<2); // then continue with the instruction the branch jumps to.
} else {
state.nextPC = state.nextPC + 4; // branch not taken
}
return outputState();
}
function handleHiLo(uint32 func, uint32 rs, uint32 rt, uint32 storeReg) internal returns (bytes32) {
State memory state;
assembly {
state := 0x80
}
uint32 val;
if (func == 0x10) val = state.hi; // mfhi
else if (func == 0x11) state.hi = rs; // mthi
else if (func == 0x12) val = state.lo; // mflo
else if (func == 0x13) state.lo = rs; // mtlo
else if (func == 0x18) { // mult
uint64 acc = uint64(int64(int32(rs))*int64(int32(rt)));
state.hi = uint32(acc>>32);
state.lo = uint32(acc);
} else if (func == 0x19) { // multu
uint64 acc = uint64(uint64(rs)*uint64(rt));
state.hi = uint32(acc>>32);
state.lo = uint32(acc);
} else if (func == 0x1a) { // div
state.hi = uint32(int32(rs)%int32(rt));
state.lo = uint32(int32(rs)/int32(rt));
} else if (func == 0x1b) { // divu
state.hi = rs%rt;
state.lo = rs/rt;
}
if (storeReg != 0) {
state.registers[storeReg] = val;
}
state.pc = state.nextPC;
state.nextPC = state.nextPC + 4;
return outputState();
}
function handleJump(uint32 linkReg, uint32 dest) internal returns (bytes32) {
State memory state;
assembly {
state := 0x80
}
uint32 prevPC = state.pc;
state.pc = state.nextPC;
state.nextPC = dest;
if (linkReg != 0) {
state.registers[linkReg] = prevPC+8; // set the link-register to the instr after the delay slot instruction.
}
return outputState();
}
function handleRd(uint32 storeReg, uint32 val, bool conditional) internal returns (bytes32) {
State memory state;
assembly {
state := 0x80
}
require(storeReg < 32, "valid register");
// never write to reg 0, and it can be conditional (movz, movn)
if (storeReg != 0 && conditional) {
state.registers[storeReg] = val;
}
state.pc = state.nextPC;
state.nextPC = state.nextPC + 4;
return outputState();
}
function proofOffset(uint8 proofIndex) internal pure returns (uint256 offset) {
// A proof of 32 bit memory, with 32-byte leaf values, is (32-5)=27 bytes32 entries.
// And the leaf value itself needs to be encoded as well. And proof.offset == 358
offset = 358 + (uint256(proofIndex) * (28*32));
uint256 s = 0;
assembly { s := calldatasize() }
require(s >= (offset + 28*32), "check that there is enough calldata");
return offset;
}
function readMem(uint32 addr, uint8 proofIndex) internal pure returns (uint32 out) {
uint256 offset = proofOffset(proofIndex);
assembly {
if and(addr, 3) { revert(0, 0) } // quick addr alignment check
let leaf := calldataload(offset)
offset := add(offset, 32)
function hashPair(a, b) -> h {
mstore(0, a) // use scratch space slots to hash the two nodes together
mstore(32, b)
h := keccak256(0, 64)
}
let path := shr(5, addr)
let node := leaf // starting from the leaf node, work back up by combining with siblings, to reconstruct the root
for { let i := 0 } lt(i, 27) { i := add(i, 1) } {
let sibling := calldataload(offset)
offset := add(offset, 32)
switch and(shr(i, path), 1)
case 0 { node := hashPair(node, sibling) }
case 1 { node := hashPair(sibling, node) }
}
let memRoot := mload(0x80) // load memRoot, first field of state
if iszero(eq(node, memRoot)) { // verify the root matches
mstore(0, 0x0badf00d)
revert(0, 32)
}
// bits to shift = (32 - 4 - (addr % 32)) * 8
let shamt := shl(3, sub(sub(32, 4), and(addr, 31)))
out := and(shr(shamt, leaf), 0xFFffFFff)
}
return out;
}
// writeMem writes the value by first overwriting the part of the leaf, and then recomputing the memory merkle root.
function writeMem(uint32 addr, uint8 proofIndex, uint32 value) internal pure {
uint256 offset = proofOffset(proofIndex);
assembly {
if and(addr, 3) { revert(0, 0) } // quick addr alignment check
let leaf := calldataload(offset)
let shamt := shl(3, sub(sub(32, 4), and(addr, 31)))
// mask out 4 bytes, and OR in the value
leaf := or(and(leaf, not(shl(shamt, 0xFFffFFff))), shl(shamt, value))
offset := add(offset, 32)
function hashPair(a, b) -> h {
mstore(0, a) // use scratch space slots to hash the two nodes together
mstore(32, b)
h := keccak256(0, 64)
}
let path := shr(5, addr)
let node := leaf // starting from the leaf node, work back up by combining with siblings, to reconstruct the root
for { let i := 0 } lt(i, 27) { i := add(i, 1) } {
let sibling := calldataload(offset)
offset := add(offset, 32)
switch and(shr(i, path), 1)
case 0 { node := hashPair(node, sibling) }
case 1 { node := hashPair(sibling, node) }
}
mstore(0x80, node) // store new memRoot, first field of state
}
}
// will revert if any required input state is missing
function Step(bytes calldata stateData, bytes calldata proof) public returns (bytes32) {
State memory state;
// packed data is ~6 times smaller
assembly {
if iszero(eq(state, 0x80)) { // expected state mem offset check
revert(0,0)
}
if iszero(eq(mload(0x40), mul(32, 48))) { // expected memory check
revert(0,0)
}
if iszero(eq(stateData.offset, 100)) { // 32*3+4=100 expected state data offset
revert(0,0)
}
if iszero(eq(proof.offset, 358)) { // 100+32+226=358 expected proof offset
revert(0,0)
}
function putField(callOffset, memOffset, size) -> callOffsetOut, memOffsetOut {
// calldata is packed, thus starting left-aligned, shift-right to pad and right-align
let w := shr(shl(3, sub(32, size)), calldataload(callOffset))
mstore(memOffset, w)
callOffsetOut := add(callOffset, size)
memOffsetOut := add(memOffset, 32)
}
let c := stateData.offset // calldata offset
let m := 0x80 // mem offset
c, m := putField(c, m, 32) // memRoot
c, m := putField(c, m, 32) // preimageKey
c, m := putField(c, m, 4) // preimageOffset
c, m := putField(c, m, 4) // pc
c, m := putField(c, m, 4) // nextPC
c, m := putField(c, m, 4) // lo
c, m := putField(c, m, 4) // hi
c, m := putField(c, m, 4) // heap
c, m := putField(c, m, 1) // exitCode
c, m := putField(c, m, 1) // exited
c, m := putField(c, m, 8) // step
mstore(m, add(m, 32)) // offset to registers
m := add(m, 32)
for { let i := 0 } lt(i, 32) { i := add(i, 1) } { c, m := putField(c, m, 4) } // registers
}
if(state.exited) { // don't change state once exited
return outputState();
}
state.step += 1;
// instruction fetch
uint32 insn = readMem(state.pc, 0);
uint32 opcode = insn >> 26; // 6-bits
// j-type j/jal
if (opcode == 2 || opcode == 3) {
// TODO(CLI-4136): likely bug in original code: MIPS spec says this should be in the "current" region;
// a 256 MB aligned region (i.e. use top 4 bits of branch delay slot (pc+4))
return handleJump(opcode == 2 ? 0 : 31, SE(insn&0x03FFFFFF, 26) << 2);
}
// register fetch
uint32 rs; // source register 1 value
uint32 rt; // source register 2 / temp value
uint32 rtReg = (insn >> 16) & 0x1F;
// R-type or I-type (stores rt)
rs = state.registers[(insn >> 21) & 0x1F];
uint32 rdReg = rtReg;
if (opcode == 0 || opcode == 0x1c) {
// R-type (stores rd)
rt = state.registers[rtReg];
rdReg = (insn >> 11) & 0x1F;
} else if (opcode < 0x20) {
// rt is SignExtImm
// don't sign extend for andi, ori, xori
if (opcode == 0xC || opcode == 0xD || opcode == 0xe) {
// ZeroExtImm
rt = insn&0xFFFF;
} else {
// SignExtImm
rt = SE(insn&0xFFFF, 16);
}
} else if (opcode >= 0x28 || opcode == 0x22 || opcode == 0x26) {
// store rt value with store
rt = state.registers[rtReg];
// store actual rt with lwl and lwr
rdReg = rtReg;
}
if ((opcode >= 4 && opcode < 8) || opcode == 1) {
return handleBranch(opcode, insn, rtReg, rs);
}
uint32 storeAddr = 0xFF_FF_FF_FF;
// memory fetch (all I-type)
// we do the load for stores also
uint32 mem;
if (opcode >= 0x20) {
// M[R[rs]+SignExtImm]
rs += SE(insn&0xFFFF, 16);
uint32 addr = rs & 0xFFFFFFFC;
mem = readMem(addr, 1);
if (opcode >= 0x28 && opcode != 0x30) {
// store
storeAddr = addr;
// store opcodes don't write back to a register
rdReg = 0;
}
}
// ALU
uint32 val = execute(insn, rs, rt, mem) & 0xffFFffFF; // swr outputs more than 4 bytes without the mask
uint32 func = insn & 0x3f; // 6-bits
if (opcode == 0 && func >= 8 && func < 0x1c) {
if (func == 8 || func == 9) { // jr/jalr
return handleJump(func == 8 ? 0 : rdReg, rs);
}
if (func == 0xa) { // movz
return handleRd(rdReg, rs, rt == 0);
}
if (func == 0xb) { // movn
return handleRd(rdReg, rs, rt != 0);
}
// syscall (can read and write)
if (func == 0xC) {
return handleSyscall();
}
// lo and hi registers
// can write back
if (func >= 0x10 && func < 0x1c) {
return handleHiLo(func, rs, rt, rdReg);
}
}
// stupid sc, write a 1 to rt
if (opcode == 0x38 && rtReg != 0) {
state.registers[rtReg] = 1;
}
// write memory
if (storeAddr != 0xFF_FF_FF_FF) {
writeMem(storeAddr, 1, val);
}
// write back the value to destination register
return handleRd(rdReg, val, true);
}
function execute(uint32 insn, uint32 rs, uint32 rt, uint32 mem) internal pure returns (uint32) {
uint32 opcode = insn >> 26; // 6-bits
uint32 func = insn & 0x3f; // 6-bits
// TODO(CLI-4136): deref the immed into a register
if (opcode < 0x20) {
// transform ArithLogI
// TODO(CLI-4136): replace with table
if (opcode >= 8 && opcode < 0xF) {
if (opcode == 8) { func = 0x20; } // addi
else if (opcode == 9) { func = 0x21; } // addiu
else if (opcode == 0xa) { func = 0x2a; } // slti
else if (opcode == 0xb) { func = 0x2B; } // sltiu
else if (opcode == 0xc) { func = 0x24; } // andi
else if (opcode == 0xd) { func = 0x25; } // ori
else if (opcode == 0xe) { func = 0x26; } // xori
opcode = 0;
}
// 0 is opcode SPECIAL
if (opcode == 0) {
uint32 shamt = (insn >> 6) & 0x1f;
if (func < 0x20) {
if (func >= 0x08) { return rs; // jr/jalr/div + others
// Shift and ShiftV
} else if (func == 0x00) { return rt << shamt; // sll
} else if (func == 0x02) { return rt >> shamt; // srl
} else if (func == 0x03) { return SE(rt >> shamt, 32-shamt); // sra
} else if (func == 0x04) { return rt << (rs&0x1F); // sllv
} else if (func == 0x06) { return rt >> (rs&0x1F); // srlv
} else if (func == 0x07) { return SE(rt >> rs, 32-rs); // srav
}
}
// 0x10-0x13 = mfhi, mthi, mflo, mtlo
// R-type (ArithLog)
if (func == 0x20 || func == 0x21) { return rs+rt; // add or addu
} else if (func == 0x22 || func == 0x23) { return rs-rt; // sub or subu
} else if (func == 0x24) { return rs&rt; // and
} else if (func == 0x25) { return (rs|rt); // or
} else if (func == 0x26) { return (rs^rt); // xor
} else if (func == 0x27) { return ~(rs|rt); // nor
} else if (func == 0x2a) {
return int32(rs)<int32(rt) ? 1 : 0; // slt
} else if (func == 0x2B) {
return rs<rt ? 1 : 0; // sltu
}
} else if (opcode == 0xf) { return rt<<16; // lui
} else if (opcode == 0x1c) { // SPECIAL2
if (func == 2) return uint32(int32(rs)*int32(rt)); // mul
if (func == 0x20 || func == 0x21) { // clo
if (func == 0x20) rs = ~rs;
uint32 i = 0; while (rs&0x80000000 != 0) { i++; rs <<= 1; } return i;
}
}
} else if (opcode < 0x28) {
if (opcode == 0x20) { // lb
return SE((mem >> (24-(rs&3)*8)) & 0xFF, 8);
} else if (opcode == 0x21) { // lh
return SE((mem >> (16-(rs&2)*8)) & 0xFFFF, 16);
} else if (opcode == 0x22) { // lwl
uint32 val = mem << ((rs&3)*8);
uint32 mask = uint32(0xFFFFFFFF) << ((rs&3)*8);
return (rt & ~mask) | val;
} else if (opcode == 0x23) { return mem; // lw
} else if (opcode == 0x24) { // lbu
return (mem >> (24-(rs&3)*8)) & 0xFF;
} else if (opcode == 0x25) { // lhu
return (mem >> (16-(rs&2)*8)) & 0xFFFF;
} else if (opcode == 0x26) { // lwr
uint32 val = mem >> (24-(rs&3)*8);
uint32 mask = uint32(0xFFFFFFFF) >> (24-(rs&3)*8);
return (rt & ~mask) | val;
}
} else if (opcode == 0x28) { // sb
uint32 val = (rt&0xFF) << (24-(rs&3)*8);
uint32 mask = 0xFFFFFFFF ^ uint32(0xFF << (24-(rs&3)*8));
return (mem & mask) | val;
} else if (opcode == 0x29) { // sh
uint32 val = (rt&0xFFFF) << (16-(rs&2)*8);
uint32 mask = 0xFFFFFFFF ^ uint32(0xFFFF << (16-(rs&2)*8));
return (mem & mask) | val;
} else if (opcode == 0x2a) { // swl
uint32 val = rt >> ((rs&3)*8);
uint32 mask = uint32(0xFFFFFFFF) >> ((rs&3)*8);
return (mem & ~mask) | val;
} else if (opcode == 0x2b) { // sw
return rt;
} else if (opcode == 0x2e) { // swr
uint32 val = rt << (24-(rs&3)*8);
uint32 mask = uint32(0xFFFFFFFF) << (24-(rs&3)*8);
return (mem & ~mask) | val;
} else if (opcode == 0x30) { return mem; // ll
} else if (opcode == 0x38) { return rt; // sc
}
revert("invalid instruction");
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
contract PreimageOracle {
mapping(bytes32 => uint256) public preimageLengths;
mapping(bytes32 => mapping(uint256 => bytes32)) public preimageParts;
mapping(bytes32 => mapping(uint256 => bool)) public preimagePartOk;
function readPreimage(bytes32 key, uint256 offset)
external
view
returns (bytes32 dat, uint256 datLen)
{
require(preimagePartOk[key][offset], "preimage must exist");
datLen = 32;
uint256 length = preimageLengths[key];
// add 8 for the length-prefix part
if (offset + 32 >= length + 8) {
datLen = length + 8 - offset;
}
dat = preimageParts[key][offset];
}
// TODO(CLI-4104):
// we need to mix-in the ID of the dispute for local-type keys to avoid collisions,
// and restrict local pre-image insertion to the dispute-managing contract.
// For now we permit anyone to write any pre-image unchecked, to make testing easy.
// This method is DANGEROUS. And NOT FOR PRODUCTION.
function cheat(
uint256 partOffset,
bytes32 key,
bytes32 part,
uint256 size
) external {
preimagePartOk[key][partOffset] = true;
preimageParts[key][partOffset] = part;
preimageLengths[key] = size;
}
// loadKeccak256PreimagePart prepares the pre-image to be read by keccak256 key,
// starting at the given offset, up to 32 bytes (clipped at preimage length, if out of data).
function loadKeccak256PreimagePart(uint256 partOffset, bytes calldata preimage) external {
uint256 size;
bytes32 key;
bytes32 part;
assembly {
// len(sig) + len(partOffset) + len(preimage offset) = 4 + 32 + 32 = 0x44
size := calldataload(0x44)
// revert if part offset >= size+8 (i.e. parts must be within bounds)
if iszero(lt(partOffset, add(size, 8))) {
revert(0, 0)
}
// we leave solidity slots 0x40 and 0x60 untouched,
// and everything after as scratch-memory.
let ptr := 0x80
// put size as big-endian uint64 at start of pre-image
mstore(ptr, shl(192, size))
ptr := add(ptr, 8)
// copy preimage payload into memory so we can hash and read it.
calldatacopy(ptr, preimage.offset, size)
// Note that it includes the 8-byte big-endian uint64 length prefix.
// this will be zero-padded at the end, since memory at end is clean.
part := mload(add(sub(ptr, 8), partOffset))
let h := keccak256(ptr, size) // compute preimage keccak256 hash
// mask out prefix byte, replace with type 2 byte
key := or(and(h, not(shl(248, 0xFF))), shl(248, 2))
}
preimagePartOk[key][partOffset] = true;
preimageParts[key][partOffset] = part;
preimageLengths[key] = size;
}
}
...@@ -136,14 +136,12 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone { ...@@ -136,14 +136,12 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
// Compute the position that the claim commits to. Because the parent's position is already // Compute the position that the claim commits to. Because the parent's position is already
// known, we can compute the next position by moving left or right depending on whether // known, we can compute the next position by moving left or right depending on whether
// or not the move is an attack or defense. // or not the move is an attack or defense.
Position nextPosition = _isAttack Position nextPosition = _isAttack ? parent.position.attack() : parent.position.defend();
? LibPosition.attack(parent.position)
: LibPosition.defend(parent.position);
// At the leaf nodes of the game, the only option is to run a step to prove or disprove // At the leaf nodes of the game, the only option is to run a step to prove or disprove
// the above claim. At this depth, the parent claim commits to the state after a single // the above claim. At this depth, the parent claim commits to the state after a single
// instruction step. // instruction step.
if (LibPosition.depth(nextPosition) >= MAX_GAME_DEPTH) { if (nextPosition.depth() >= MAX_GAME_DEPTH) {
revert GameDepthExceeded(); revert GameDepthExceeded();
} }
...@@ -160,11 +158,11 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone { ...@@ -160,11 +158,11 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
Duration nextDuration = Duration.wrap( Duration nextDuration = Duration.wrap(
uint64( uint64(
// First, fetch the duration of the grandparent claim. // First, fetch the duration of the grandparent claim.
Duration.unwrap(LibClock.duration(grandparentClock)) + Duration.unwrap(grandparentClock.duration()) +
// Second, add the difference between the current block timestamp and the // Second, add the difference between the current block timestamp and the
// parent's clock timestamp. // parent's clock timestamp.
block.timestamp - block.timestamp -
Timestamp.unwrap(LibClock.timestamp(parent.clock)) Timestamp.unwrap(parent.clock.timestamp())
) )
); );
...@@ -178,7 +176,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone { ...@@ -178,7 +176,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
Clock nextClock = LibClock.wrap(nextDuration, Timestamp.wrap(uint64(block.timestamp))); Clock nextClock = LibClock.wrap(nextDuration, Timestamp.wrap(uint64(block.timestamp)));
// Do not allow for a duplicate claim to be made. // Do not allow for a duplicate claim to be made.
ClaimHash claimHash = LibHashing.hashClaimPos(_pivot, nextPosition); ClaimHash claimHash = _pivot.hashClaimPos(nextPosition);
if (claims[claimHash]) { if (claims[claimHash]) {
revert ClaimAlreadyExists(); revert ClaimAlreadyExists();
} }
...@@ -221,9 +219,56 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone { ...@@ -221,9 +219,56 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
* @inheritdoc IDisputeGame * @inheritdoc IDisputeGame
*/ */
function resolve() external returns (GameStatus status_) { function resolve() external returns (GameStatus status_) {
// TODO - Resolve the game if (status != GameStatus.IN_PROGRESS) {
status = GameStatus.IN_PROGRESS; revert GameNotInProgress();
status_ = status; }
// Search for the left-most dangling non-bottom node
// The most recent claim is always a dangling, non-bottom node so we start with that
uint256 leftMostIndex = claimData.length - 1;
uint256 leftMostTraceIndex = LibPosition.rightIndex(
claimData[leftMostIndex].position,
MAX_GAME_DEPTH
);
for (uint256 i = leftMostIndex; i < type(uint64).max; ) {
// Fetch the claim at the current index.
ClaimData storage claim = claimData[i];
// Decrement the loop counter; If it underflows, we've reached the root
// claim and can stop searching.
unchecked {
--i;
}
// If the claim is not a dangling node above the bottom of the tree,
// we can skip over it. These nodes are not relevant to the game resolution.
Position claimPos = claim.position;
if (LibPosition.depth(claimPos) == MAX_GAME_DEPTH || claim.countered) {
continue;
}
// If the claim is a dangling node, we can check if it is the left-most
// dangling node we've come across so far. If it is, we can update the
// left-most trace index.
uint256 traceIndex = LibPosition.rightIndex(claimPos, MAX_GAME_DEPTH);
if (traceIndex < leftMostTraceIndex) {
leftMostTraceIndex = traceIndex;
leftMostIndex = i + 1;
}
}
// If the left-most dangling node is at an even depth, the defender wins.
// Otherwise, the challenger wins and the root claim is deemed invalid.
// slither-disable-next-line weak-prng
if (LibPosition.depth(claimData[leftMostIndex].position) % 2 == 0) {
status_ = GameStatus.DEFENDER_WINS;
} else {
status_ = GameStatus.CHALLENGER_WINS;
}
// Update the game status
status = status_;
emit Resolved(status_);
} }
/** /**
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.15; pragma solidity ^0.8.15;
import { LibHashing } from "../dispute/lib/LibHashing.sol";
import { LibPosition } from "../dispute/lib/LibPosition.sol";
import { LibClock } from "../dispute/lib/LibClock.sol";
using LibHashing for Claim global;
using LibPosition for Position global;
using LibClock for Clock global;
/** /**
* @notice A custom type for a generic hash. * @notice A custom type for a generic hash.
*/ */
......
...@@ -247,7 +247,7 @@ contract FaultDisputeGame_Test is DisputeGameFactory_Init { ...@@ -247,7 +247,7 @@ contract FaultDisputeGame_Test is DisputeGameFactory_Init {
assertEq(parentIndex, 0); assertEq(parentIndex, 0);
assertEq(countered, false); assertEq(countered, false);
assertEq(Claim.unwrap(claim), Claim.unwrap(counter)); assertEq(Claim.unwrap(claim), Claim.unwrap(counter));
assertEq(Position.unwrap(position), Position.unwrap(LibPosition.attack(Position.wrap(1)))); assertEq(Position.unwrap(position), Position.unwrap(Position.wrap(1).attack()));
assertEq( assertEq(
Clock.unwrap(clock), Clock.unwrap(clock),
Clock.unwrap(LibClock.wrap(Duration.wrap(5), Timestamp.wrap(uint64(block.timestamp)))) Clock.unwrap(LibClock.wrap(Duration.wrap(5), Timestamp.wrap(uint64(block.timestamp))))
...@@ -268,6 +268,61 @@ contract FaultDisputeGame_Test is DisputeGameFactory_Init { ...@@ -268,6 +268,61 @@ contract FaultDisputeGame_Test is DisputeGameFactory_Init {
) )
); );
} }
/**
* @dev Static unit test for the correctness an uncontested root resolution.
*/
function test_resolve_rootUncontested() public {
GameStatus status = gameProxy.resolve();
assertEq(uint8(status), uint8(GameStatus.DEFENDER_WINS));
assertEq(uint8(gameProxy.status()), uint8(GameStatus.DEFENDER_WINS));
}
/**
* @dev Static unit test asserting that resolve reverts when the game is not in progress.
*/
function test_resolve_reverts() public {
gameProxy.resolve();
vm.expectRevert(GameNotInProgress.selector);
gameProxy.resolve();
}
/**
* @dev Static unit test for the correctness of resolving a single attack game state.
*/
function test_resolve_rootContested() public {
gameProxy.attack(0, Claim.wrap(bytes32(uint256(5))));
GameStatus status = gameProxy.resolve();
assertEq(uint8(status), uint8(GameStatus.CHALLENGER_WINS));
assertEq(uint8(gameProxy.status()), uint8(GameStatus.CHALLENGER_WINS));
}
/**
* @dev Static unit test for the correctness of resolving a game with a contested challenge claim.
*/
function test_resolve_challengeContested() public {
gameProxy.attack(0, Claim.wrap(bytes32(uint256(5))));
gameProxy.defend(1, Claim.wrap(bytes32(uint256(6))));
GameStatus status = gameProxy.resolve();
assertEq(uint8(status), uint8(GameStatus.DEFENDER_WINS));
assertEq(uint8(gameProxy.status()), uint8(GameStatus.DEFENDER_WINS));
}
/**
* @dev Static unit test for the correctness of resolving a game with multiplayer moves.
*/
function test_resolve_teamDeathmatch() public {
gameProxy.attack(0, Claim.wrap(bytes32(uint256(5))));
gameProxy.attack(0, Claim.wrap(bytes32(uint256(4))));
gameProxy.defend(1, Claim.wrap(bytes32(uint256(6))));
gameProxy.defend(1, Claim.wrap(bytes32(uint256(7))));
GameStatus status = gameProxy.resolve();
assertEq(uint8(status), uint8(GameStatus.CHALLENGER_WINS));
assertEq(uint8(gameProxy.status()), uint8(GameStatus.CHALLENGER_WINS));
}
} }
/** /**
......
...@@ -14,7 +14,7 @@ contract LibClock_Test is Test { ...@@ -14,7 +14,7 @@ contract LibClock_Test is Test {
*/ */
function testFuzz_duration_succeeds(Duration _duration, Timestamp _timestamp) public { function testFuzz_duration_succeeds(Duration _duration, Timestamp _timestamp) public {
Clock clock = LibClock.wrap(_duration, _timestamp); Clock clock = LibClock.wrap(_duration, _timestamp);
assertEq(Duration.unwrap(LibClock.duration(clock)), Duration.unwrap(_duration)); assertEq(Duration.unwrap(clock.duration()), Duration.unwrap(_duration));
} }
/** /**
...@@ -22,6 +22,6 @@ contract LibClock_Test is Test { ...@@ -22,6 +22,6 @@ contract LibClock_Test is Test {
*/ */
function testFuzz_timestamp_succeeds(Duration _duration, Timestamp _timestamp) public { function testFuzz_timestamp_succeeds(Duration _duration, Timestamp _timestamp) public {
Clock clock = LibClock.wrap(_duration, _timestamp); Clock clock = LibClock.wrap(_duration, _timestamp);
assertEq(Timestamp.unwrap(LibClock.timestamp(clock)), Timestamp.unwrap(_timestamp)); assertEq(Timestamp.unwrap(clock.timestamp()), Timestamp.unwrap(_timestamp));
} }
} }
...@@ -32,7 +32,7 @@ contract LibPosition_Test is Test { ...@@ -32,7 +32,7 @@ contract LibPosition_Test is Test {
_depth = uint8(bound(_depth, 0, MAX_DEPTH)); _depth = uint8(bound(_depth, 0, MAX_DEPTH));
_indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth); _indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth);
Position position = LibPosition.wrap(_depth, _indexAtDepth); Position position = LibPosition.wrap(_depth, _indexAtDepth);
assertEq(LibPosition.depth(position), _depth); assertEq(position.depth(), _depth);
} }
/** /**
...@@ -42,7 +42,7 @@ contract LibPosition_Test is Test { ...@@ -42,7 +42,7 @@ contract LibPosition_Test is Test {
_depth = uint8(bound(_depth, 0, MAX_DEPTH)); _depth = uint8(bound(_depth, 0, MAX_DEPTH));
_indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth); _indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth);
Position position = LibPosition.wrap(_depth, _indexAtDepth); Position position = LibPosition.wrap(_depth, _indexAtDepth);
assertEq(LibPosition.indexAtDepth(position), _indexAtDepth); assertEq(position.indexAtDepth(), _indexAtDepth);
} }
/** /**
...@@ -53,10 +53,10 @@ contract LibPosition_Test is Test { ...@@ -53,10 +53,10 @@ contract LibPosition_Test is Test {
_indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth); _indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth);
Position position = LibPosition.wrap(_depth, _indexAtDepth); Position position = LibPosition.wrap(_depth, _indexAtDepth);
Position left = LibPosition.left(position); Position left = position.left();
assertEq(LibPosition.depth(left), uint64(_depth) + 1); assertEq(left.depth(), uint64(_depth) + 1);
assertEq(LibPosition.indexAtDepth(left), _indexAtDepth * 2); assertEq(left.indexAtDepth(), _indexAtDepth * 2);
} }
/** /**
...@@ -68,10 +68,10 @@ contract LibPosition_Test is Test { ...@@ -68,10 +68,10 @@ contract LibPosition_Test is Test {
_indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth); _indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth);
Position position = LibPosition.wrap(_depth, _indexAtDepth); Position position = LibPosition.wrap(_depth, _indexAtDepth);
Position right = LibPosition.right(position); Position right = position.right();
assertEq(LibPosition.depth(right), _depth + 1); assertEq(right.depth(), _depth + 1);
assertEq(LibPosition.indexAtDepth(right), _indexAtDepth * 2 + 1); assertEq(right.indexAtDepth(), _indexAtDepth * 2 + 1);
} }
/** /**
...@@ -82,10 +82,10 @@ contract LibPosition_Test is Test { ...@@ -82,10 +82,10 @@ contract LibPosition_Test is Test {
_indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth); _indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth);
Position position = LibPosition.wrap(_depth, _indexAtDepth); Position position = LibPosition.wrap(_depth, _indexAtDepth);
Position parent = LibPosition.parent(position); Position parent = position.parent();
assertEq(LibPosition.depth(parent), _depth - 1); assertEq(parent.depth(), _depth - 1);
assertEq(LibPosition.indexAtDepth(parent), _indexAtDepth / 2); assertEq(parent.indexAtDepth(), _indexAtDepth / 2);
} }
/** /**
...@@ -105,13 +105,13 @@ contract LibPosition_Test is Test { ...@@ -105,13 +105,13 @@ contract LibPosition_Test is Test {
_indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth); _indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth);
Position position = LibPosition.wrap(_depth, _indexAtDepth); Position position = LibPosition.wrap(_depth, _indexAtDepth);
uint64 rightIndex = LibPosition.rightIndex(position, _maxDepth); uint64 rightIndex = position.rightIndex(_maxDepth);
// Find the deepest, rightmost index in Solidity rather than Yul // Find the deepest, rightmost index in Solidity rather than Yul
for (uint256 i = _depth; i < _maxDepth; ++i) { for (uint256 i = _depth; i < _maxDepth; ++i) {
position = LibPosition.right(position); position = position.right();
} }
uint64 _rightIndex = LibPosition.indexAtDepth(position); uint64 _rightIndex = position.indexAtDepth();
assertEq(rightIndex, _rightIndex); assertEq(rightIndex, _rightIndex);
} }
...@@ -127,10 +127,10 @@ contract LibPosition_Test is Test { ...@@ -127,10 +127,10 @@ contract LibPosition_Test is Test {
_indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth); _indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth);
Position position = LibPosition.wrap(_depth, _indexAtDepth); Position position = LibPosition.wrap(_depth, _indexAtDepth);
Position attack = LibPosition.attack(position); Position attack = position.attack();
assertEq(LibPosition.depth(attack), _depth + 1); assertEq(attack.depth(), _depth + 1);
assertEq(LibPosition.indexAtDepth(attack), _indexAtDepth * 2); assertEq(attack.indexAtDepth(), _indexAtDepth * 2);
} }
/** /**
...@@ -145,9 +145,9 @@ contract LibPosition_Test is Test { ...@@ -145,9 +145,9 @@ contract LibPosition_Test is Test {
_indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth); _indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth);
Position position = LibPosition.wrap(_depth, _indexAtDepth); Position position = LibPosition.wrap(_depth, _indexAtDepth);
Position defend = LibPosition.defend(position); Position defend = position.defend();
assertEq(LibPosition.depth(defend), _depth + 1); assertEq(defend.depth(), _depth + 1);
assertEq(LibPosition.indexAtDepth(defend), ((_indexAtDepth / 2) * 2 + 1) * 2); assertEq(defend.indexAtDepth(), ((_indexAtDepth / 2) * 2 + 1) * 2);
} }
} }
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { StdUtils } from "forge-std/Test.sol";
import { Vm } from "forge-std/Vm.sol";
import { OptimismPortal } from "../../L1/OptimismPortal.sol";
import { L2OutputOracle } from "../../L1/L2OutputOracle.sol";
import { AddressAliasHelper } from "../../vendor/AddressAliasHelper.sol";
import { SystemConfig } from "../../L1/SystemConfig.sol";
import { ResourceMetering } from "../../L1/ResourceMetering.sol";
import { Constants } from "../../libraries/Constants.sol";
import { Portal_Initializer } from "../CommonTest.t.sol"; import { Portal_Initializer } from "../CommonTest.t.sol";
import { Types } from "../../libraries/Types.sol"; import { Types } from "../../libraries/Types.sol";
contract OptimismPortal_Depositor is StdUtils, ResourceMetering {
Vm internal vm;
OptimismPortal internal portal;
bool public failedToComplete;
constructor(Vm _vm, OptimismPortal _portal) {
vm = _vm;
portal = _portal;
initialize();
}
function initialize() internal initializer {
__ResourceMetering_init();
}
function resourceConfig() public pure returns (ResourceMetering.ResourceConfig memory) {
return _resourceConfig();
}
function _resourceConfig()
internal
pure
override
returns (ResourceMetering.ResourceConfig memory)
{
ResourceMetering.ResourceConfig memory rcfg = Constants.DEFAULT_RESOURCE_CONFIG();
return rcfg;
}
// A test intended to identify any unexpected halting conditions
function depositTransactionCompletes(
address _to,
uint256 _value,
uint64 _gasLimit,
bool _isCreation,
bytes memory _data
) public payable {
vm.assume((!_isCreation || _to == address(0)) && _data.length <= 120_000);
uint256 preDepositvalue = bound(_value, 0, type(uint128).max);
// Give the depositor some ether
vm.deal(address(this), preDepositvalue);
// cache the contract's eth balance
uint256 preDepositBalance = address(this).balance;
uint256 value = bound(preDepositvalue, 0, preDepositBalance);
(, uint64 cachedPrevBoughtGas, ) = ResourceMetering(address(portal)).params();
ResourceMetering.ResourceConfig memory rcfg = resourceConfig();
uint256 maxResourceLimit = uint64(rcfg.maxResourceLimit);
uint64 gasLimit = uint64(
bound(
_gasLimit,
portal.minimumGasLimit(uint64(_data.length)),
maxResourceLimit - cachedPrevBoughtGas
)
);
try portal.depositTransaction{ value: value }(_to, value, gasLimit, _isCreation, _data) {
// Do nothing; Call succeeded
} catch {
failedToComplete = true;
}
}
}
contract OptimismPortal_Invariant_Harness is Portal_Initializer { contract OptimismPortal_Invariant_Harness is Portal_Initializer {
// Reusable default values for a test withdrawal // Reusable default values for a test withdrawal
Types.WithdrawalTransaction _defaultTx; Types.WithdrawalTransaction _defaultTx;
...@@ -57,6 +132,34 @@ contract OptimismPortal_Invariant_Harness is Portal_Initializer { ...@@ -57,6 +132,34 @@ contract OptimismPortal_Invariant_Harness is Portal_Initializer {
} }
} }
contract OptimismPortal_Deposit_Invariant is Portal_Initializer {
OptimismPortal_Depositor internal actor;
function setUp() public override {
super.setUp();
// Create a deposit actor.
actor = new OptimismPortal_Depositor(vm, op);
targetContract(address(actor));
bytes4[] memory selectors = new bytes4[](1);
selectors[0] = actor.depositTransactionCompletes.selector;
FuzzSelector memory selector = FuzzSelector({ addr: address(actor), selectors: selectors });
targetSelector(selector);
}
/**
* @custom:invariant Deposits of any value should always succeed unless
* `_to` = `address(0)` or `_isCreation` = `true`.
*
* All deposits, barring creation transactions and transactions sent to `address(0)`,
* should always succeed.
*/
function invariant_deposit_completes() external {
assertEq(actor.failedToComplete(), false);
}
}
contract OptimismPortal_CannotTimeTravel is OptimismPortal_Invariant_Harness { contract OptimismPortal_CannotTimeTravel is OptimismPortal_Invariant_Harness {
function setUp() public override { function setUp() public override {
super.setUp(); super.setUp();
......
# `OptimismPortal` Invariants # `OptimismPortal` Invariants
## Deposits of any value should always succeed unless `_to` = `address(0)` or `_isCreation` = `true`.
**Test:** [`OptimismPortal.t.sol#L158`](../contracts/test/invariants/OptimismPortal.t.sol#L158)
All deposits, barring creation transactions and transactions sent to `address(0)`, should always succeed.
## `finalizeWithdrawalTransaction` should revert if the finalization period has not elapsed. ## `finalizeWithdrawalTransaction` should revert if the finalization period has not elapsed.
**Test:** [`OptimismPortal.t.sol#L85`](../contracts/test/invariants/OptimismPortal.t.sol#L85) **Test:** [`OptimismPortal.t.sol#L188`](../contracts/test/invariants/OptimismPortal.t.sol#L188)
A withdrawal that has been proven should not be able to be finalized until after the finalization period has elapsed. A withdrawal that has been proven should not be able to be finalized until after the finalization period has elapsed.
## `finalizeWithdrawalTransaction` should revert if the withdrawal has already been finalized. ## `finalizeWithdrawalTransaction` should revert if the withdrawal has already been finalized.
**Test:** [`OptimismPortal.t.sol#L122`](../contracts/test/invariants/OptimismPortal.t.sol#L122) **Test:** [`OptimismPortal.t.sol#L225`](../contracts/test/invariants/OptimismPortal.t.sol#L225)
Ensures that there is no chain of calls that can be made that allows a withdrawal to be finalized twice. Ensures that there is no chain of calls that can be made that allows a withdrawal to be finalized twice.
## A withdrawal should **always** be able to be finalized `FINALIZATION_PERIOD_SECONDS` after it was successfully proven. ## A withdrawal should **always** be able to be finalized `FINALIZATION_PERIOD_SECONDS` after it was successfully proven.
**Test:** [`OptimismPortal.t.sol#L157`](../contracts/test/invariants/OptimismPortal.t.sol#L157) **Test:** [`OptimismPortal.t.sol#L260`](../contracts/test/invariants/OptimismPortal.t.sol#L260)
This invariant asserts that there is no chain of calls that can be made that will prevent a withdrawal from being finalized exactly `FINALIZATION_PERIOD_SECONDS` after it was successfully proven. This invariant asserts that there is no chain of calls that can be made that will prevent a withdrawal from being finalized exactly `FINALIZATION_PERIOD_SECONDS` after it was successfully proven.
......
{ {
"name": "@eth-optimism/contracts-bedrock", "name": "@eth-optimism/contracts-bedrock",
"version": "0.14.0", "version": "0.15.0",
"description": "Contracts for Optimism Specs", "description": "Contracts for Optimism Specs",
"main": "dist/index", "main": "dist/index",
"types": "dist/index", "types": "dist/index",
...@@ -37,10 +37,10 @@ ...@@ -37,10 +37,10 @@
"clean": "rm -rf ./dist ./artifacts ./forge-artifacts ./cache ./tsconfig.tsbuildinfo ./tsconfig.build.tsbuildinfo ./src/contract-artifacts.ts ./test-case-generator/fuzz", "clean": "rm -rf ./dist ./artifacts ./forge-artifacts ./cache ./tsconfig.tsbuildinfo ./tsconfig.build.tsbuildinfo ./src/contract-artifacts.ts ./test-case-generator/fuzz",
"lint:ts:check": "eslint . --max-warnings=0", "lint:ts:check": "eslint . --max-warnings=0",
"lint:forge-tests:check": "ts-node scripts/forge-test-names.ts", "lint:forge-tests:check": "ts-node scripts/forge-test-names.ts",
"lint:contracts:check": "yarn solhint -f table 'contracts/**/*.sol' && yarn prettier --check 'contracts/**/*.sol' && yarn lint:forge-tests:check", "lint:contracts:check": "yarn solhint -f table 'contracts/**/!(DisputeTypes).sol' && yarn prettier --check 'contracts/**/!(DisputeTypes).sol' && yarn lint:forge-tests:check",
"lint:check": "yarn lint:contracts:check && yarn lint:ts:check", "lint:check": "yarn lint:contracts:check && yarn lint:ts:check",
"lint:ts:fix": "eslint --fix .", "lint:ts:fix": "eslint --fix .",
"lint:contracts:fix": "yarn solhint --fix 'contracts/**/*.sol' && yarn prettier --write 'contracts/**/*.sol'", "lint:contracts:fix": "yarn solhint --fix 'contracts/**/!(DisputeTypes).sol' && yarn prettier --write 'contracts/**/!(DisputeTypes).sol'",
"lint:fix": "yarn lint:contracts:fix && yarn lint:ts:fix", "lint:fix": "yarn lint:contracts:fix && yarn lint:ts:fix",
"lint": "yarn lint:fix && yarn lint:check", "lint": "yarn lint:fix && yarn lint:check",
"typechain": "typechain --target ethers-v5 --out-dir dist/types --glob 'artifacts/!(build-info)/**/+([a-zA-Z0-9_]).json'", "typechain": "typechain --target ethers-v5 --out-dir dist/types --glob 'artifacts/!(build-info)/**/+([a-zA-Z0-9_]).json'",
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
"echidna:metering": "echidna-test --contract EchidnaFuzzResourceMetering --config ./echidna.yaml ." "echidna:metering": "echidna-test --contract EchidnaFuzzResourceMetering --config ./echidna.yaml ."
}, },
"dependencies": { "dependencies": {
"@eth-optimism/core-utils": "^0.12.0", "@eth-optimism/core-utils": "^0.12.1",
"@openzeppelin/contracts": "4.7.3", "@openzeppelin/contracts": "4.7.3",
"@openzeppelin/contracts-upgradeable": "4.7.3", "@openzeppelin/contracts-upgradeable": "4.7.3",
"ethers": "^5.7.0" "ethers": "^5.7.0"
......
...@@ -10,6 +10,6 @@ ...@@ -10,6 +10,6 @@
"hardhat_ignore_compile": false, "hardhat_ignore_compile": false,
"disable_color": false, "disable_color": false,
"exclude_dependencies": true, "exclude_dependencies": true,
"filter_paths": "contracts/test,contracts/vendor,contracts/echidna,node_modules", "filter_paths": "contracts/test,contracts/vendor,contracts/echidna,node_modules,contracts/cannon/MIPS.sol",
"foundry_out_directory": "artifacts" "foundry_out_directory": "artifacts"
} }
...@@ -53,8 +53,8 @@ ...@@ -53,8 +53,8 @@
"url": "https://github.com/ethereum-optimism/optimism.git" "url": "https://github.com/ethereum-optimism/optimism.git"
}, },
"devDependencies": { "devDependencies": {
"@eth-optimism/contracts-bedrock": "0.14.0", "@eth-optimism/contracts-bedrock": "0.15.0",
"@eth-optimism/core-utils": "^0.12.0", "@eth-optimism/core-utils": "^0.12.1",
"@eth-optimism/hardhat-deploy-config": "^0.2.6", "@eth-optimism/hardhat-deploy-config": "^0.2.6",
"@ethersproject/hardware-wallets": "^5.7.0", "@ethersproject/hardware-wallets": "^5.7.0",
"@nomiclabs/hardhat-ethers": "^2.0.2", "@nomiclabs/hardhat-ethers": "^2.0.2",
......
# @eth-optimism/core-utils # @eth-optimism/core-utils
## 0.12.1
### Patch Changes
- 8d7dcc70c: Delete legacy core-utils
- d6388be4a: Added a new service wallet-mon to identify unexpected transfers from key accounts
## 0.12.0 ## 0.12.0
### Minor Changes ### Minor Changes
......
{ {
"name": "@eth-optimism/core-utils", "name": "@eth-optimism/core-utils",
"version": "0.12.0", "version": "0.12.1",
"description": "[Optimism] Core typescript utilities", "description": "[Optimism] Core typescript utilities",
"main": "dist/index", "main": "dist/index",
"types": "dist/index", "types": "dist/index",
......
declare module 'bufio' {
class BufferWriter {
public offset: number
constructor()
render(): Buffer
getSize(): number
seek(offset: number): this
destroy(): this
writeU8(n: number): this
writeU16(n: number): this
writeU16BE(n: number): this
writeU24(n: number): this
writeU24BE(n: number): this
writeU32(n: number): this
writeU32BE(n: number): this
writeU40(n: number): this
writeU40BE(n: number): this
writeU48(n: number): this
writeU48BE(n: number): this
writeU56(n: number): this
writeU56BE(n: number): this
writeU64(n: number): this
writeU64BE(n: number): this
writeBytes(b: Buffer): this
copy(value: number, start: number, end: number): this
}
class BufferReader {
constructor(data: Buffer, copy?: boolean)
getSize(): number
check(n: number): void
left(): number
seek(offset: number): this
start(): number
end(): number
destroy(): this
readU8(): number
readU16(): number
readU16BE(): number
readU24(): number
readU24BE(): number
readU32(): number
readU32BE(): number
readU40(): number
readU40BE(): number
readU48(): number
readU48BE(): number
readU56(): number
readU56BE(): number
readU64(): number
readU64BE(): number
readBytes(size: number, copy?: boolean): Buffer
}
class Struct {
constructor()
encode(extra?: object): Buffer
decode<T extends Struct>(data: Buffer, extra?: object): T
getSize(extra?: object): number
fromHex(s: string, extra?: object): this
toHex(): string
write(bw: BufferWriter, extra?: object): BufferWriter
read(br: BufferReader, extra?: object): this
static read<T extends Struct>(br: BufferReader, extra?: object): T
static decode<T extends Struct>(data: Buffer, extra?: object): T
static fromHex<T extends Struct>(s: string, extra?: object): T
}
}
# @eth-optimism/fault-detector # @eth-optimism/fault-detector
## 1.0.0
### Major Changes
- 119754c2f: Make optimism/sdk default to bedrock mode
### Patch Changes
- 16ccbee24: Fix false error to warning
- 685addec2: Add better source maps and developer support
- Updated dependencies [8d7dcc70c]
- Updated dependencies [119754c2f]
- Updated dependencies [d6388be4a]
- @eth-optimism/core-utils@0.12.1
- @eth-optimism/sdk@3.0.0
- @eth-optimism/common-ts@0.8.2
## 0.6.4 ## 0.6.4
### Patch Changes ### Patch Changes
......
{ {
"private": true, "private": true,
"name": "@eth-optimism/fault-detector", "name": "@eth-optimism/fault-detector",
"version": "0.6.4", "version": "1.0.0",
"description": "[Optimism] Service for detecting faulty L2 output proposals", "description": "[Optimism] Service for detecting faulty L2 output proposals",
"main": "dist/index", "main": "dist/index",
"types": "dist/index", "types": "dist/index",
...@@ -50,10 +50,10 @@ ...@@ -50,10 +50,10 @@
"tsx": "^3.12.7" "tsx": "^3.12.7"
}, },
"dependencies": { "dependencies": {
"@eth-optimism/common-ts": "^0.8.1", "@eth-optimism/common-ts": "^0.8.2",
"@eth-optimism/contracts": "^0.6.0", "@eth-optimism/contracts": "^0.6.0",
"@eth-optimism/core-utils": "^0.12.0", "@eth-optimism/core-utils": "^0.12.1",
"@eth-optimism/sdk": "^2.1.0", "@eth-optimism/sdk": "^3.0.0",
"@ethersproject/abstract-provider": "^5.7.0" "@ethersproject/abstract-provider": "^5.7.0"
} }
} }
# @eth-optimism/replica-healthcheck # @eth-optimism/replica-healthcheck
## 1.2.5
### Patch Changes
- Updated dependencies [8d7dcc70c]
- Updated dependencies [d6388be4a]
- @eth-optimism/core-utils@0.12.1
- @eth-optimism/common-ts@0.8.2
## 1.2.4 ## 1.2.4
### Patch Changes ### Patch Changes
......
{ {
"private": true, "private": true,
"name": "@eth-optimism/replica-healthcheck", "name": "@eth-optimism/replica-healthcheck",
"version": "1.2.4", "version": "1.2.5",
"description": "[Optimism] Service for monitoring the health of replica nodes", "description": "[Optimism] Service for monitoring the health of replica nodes",
"main": "dist/index", "main": "dist/index",
"types": "dist/index", "types": "dist/index",
...@@ -32,8 +32,8 @@ ...@@ -32,8 +32,8 @@
"url": "https://github.com/ethereum-optimism/optimism.git" "url": "https://github.com/ethereum-optimism/optimism.git"
}, },
"dependencies": { "dependencies": {
"@eth-optimism/common-ts": "0.8.1", "@eth-optimism/common-ts": "0.8.2",
"@eth-optimism/core-utils": "0.12.0", "@eth-optimism/core-utils": "0.12.1",
"@ethersproject/abstract-provider": "^5.7.0" "@ethersproject/abstract-provider": "^5.7.0"
}, },
"devDependencies": { "devDependencies": {
......
# @eth-optimism/sdk # @eth-optimism/sdk
## 3.0.0
### Major Changes
- 119754c2f: Make optimism/sdk default to bedrock mode
### Patch Changes
- Updated dependencies [8d7dcc70c]
- Updated dependencies [d6388be4a]
- Updated dependencies [af292562f]
- @eth-optimism/core-utils@0.12.1
- @eth-optimism/contracts-bedrock@0.15.0
## 2.1.0 ## 2.1.0
### Minor Changes ### Minor Changes
......
{ {
"name": "@eth-optimism/sdk", "name": "@eth-optimism/sdk",
"version": "2.1.0", "version": "3.0.0",
"description": "[Optimism] Tools for working with Optimism", "description": "[Optimism] Tools for working with Optimism",
"main": "dist/index", "main": "dist/index",
"types": "dist/index", "types": "dist/index",
...@@ -55,8 +55,8 @@ ...@@ -55,8 +55,8 @@
}, },
"dependencies": { "dependencies": {
"@eth-optimism/contracts": "0.6.0", "@eth-optimism/contracts": "0.6.0",
"@eth-optimism/core-utils": "0.12.0", "@eth-optimism/core-utils": "0.12.1",
"@eth-optimism/contracts-bedrock": "0.14.0", "@eth-optimism/contracts-bedrock": "0.15.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"merkletreejs": "^0.2.27", "merkletreejs": "^0.2.27",
"rlp": "^2.2.7" "rlp": "^2.2.7"
......
...@@ -778,6 +778,28 @@ ...@@ -778,6 +778,28 @@
"@ethersproject/abstract-provider" "^5.7.0" "@ethersproject/abstract-provider" "^5.7.0"
"@ethersproject/abstract-signer" "^5.7.0" "@ethersproject/abstract-signer" "^5.7.0"
"@eth-optimism/core-utils@0.12.0":
version "0.12.0"
resolved "https://registry.yarnpkg.com/@eth-optimism/core-utils/-/core-utils-0.12.0.tgz#6337e4599a34de23f8eceb20378de2a2de82b0ea"
integrity sha512-qW+7LZYCz7i8dRa7SRlUKIo1VBU8lvN0HeXCxJR+z+xtMzMQpPds20XJNCMclszxYQHkXY00fOT6GvFw9ZL6nw==
dependencies:
"@ethersproject/abi" "^5.7.0"
"@ethersproject/abstract-provider" "^5.7.0"
"@ethersproject/address" "^5.7.0"
"@ethersproject/bignumber" "^5.7.0"
"@ethersproject/bytes" "^5.7.0"
"@ethersproject/constants" "^5.7.0"
"@ethersproject/contracts" "^5.7.0"
"@ethersproject/hash" "^5.7.0"
"@ethersproject/keccak256" "^5.7.0"
"@ethersproject/properties" "^5.7.0"
"@ethersproject/providers" "^5.7.0"
"@ethersproject/rlp" "^5.7.0"
"@ethersproject/transactions" "^5.7.0"
"@ethersproject/web" "^5.7.0"
bufio "^1.0.7"
chai "^4.3.4"
"@ethereum-waffle/chai@^3.4.0": "@ethereum-waffle/chai@^3.4.0":
version "3.4.0" version "3.4.0"
resolved "https://registry.yarnpkg.com/@ethereum-waffle/chai/-/chai-3.4.0.tgz#2477877410a96bf370edd64df905b04fb9aba9d5" resolved "https://registry.yarnpkg.com/@ethereum-waffle/chai/-/chai-3.4.0.tgz#2477877410a96bf370edd64df905b04fb9aba9d5"
...@@ -1692,6 +1714,32 @@ ...@@ -1692,6 +1714,32 @@
bech32 "1.1.4" bech32 "1.1.4"
ws "7.4.6" ws "7.4.6"
"@ethersproject/providers@^5.7.0":
version "5.7.2"
resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb"
integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==
dependencies:
"@ethersproject/abstract-provider" "^5.7.0"
"@ethersproject/abstract-signer" "^5.7.0"
"@ethersproject/address" "^5.7.0"
"@ethersproject/base64" "^5.7.0"
"@ethersproject/basex" "^5.7.0"
"@ethersproject/bignumber" "^5.7.0"
"@ethersproject/bytes" "^5.7.0"
"@ethersproject/constants" "^5.7.0"
"@ethersproject/hash" "^5.7.0"
"@ethersproject/logger" "^5.7.0"
"@ethersproject/networks" "^5.7.0"
"@ethersproject/properties" "^5.7.0"
"@ethersproject/random" "^5.7.0"
"@ethersproject/rlp" "^5.7.0"
"@ethersproject/sha2" "^5.7.0"
"@ethersproject/strings" "^5.7.0"
"@ethersproject/transactions" "^5.7.0"
"@ethersproject/web" "^5.7.0"
bech32 "1.1.4"
ws "7.4.6"
"@ethersproject/random@5.4.0", "@ethersproject/random@^5.4.0": "@ethersproject/random@5.4.0", "@ethersproject/random@^5.4.0":
version "5.4.0" version "5.4.0"
resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.4.0.tgz#9cdde60e160d024be39cc16f8de3b9ce39191e16" resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.4.0.tgz#9cdde60e160d024be39cc16f8de3b9ce39191e16"
...@@ -5683,6 +5731,11 @@ bufferutil@^4.0.1: ...@@ -5683,6 +5731,11 @@ bufferutil@^4.0.1:
dependencies: dependencies:
node-gyp-build "^4.2.0" node-gyp-build "^4.2.0"
bufio@^1.0.7:
version "1.2.0"
resolved "https://registry.yarnpkg.com/bufio/-/bufio-1.2.0.tgz#b9ad1c06b0d9010363c387c39d2810a7086d143f"
integrity sha512-UlFk8z/PwdhYQTXSQQagwGAdtRI83gib2n4uy4rQnenxUM2yQi8lBDzF230BNk+3wAoZDxYRoBwVVUPgHa9MCA==
builtin-modules@^3.0.0: builtin-modules@^3.0.0:
version "3.2.0" version "3.2.0"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.2.0.tgz#45d5db99e7ee5e6bc4f362e008bf917ab5049887" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.2.0.tgz#45d5db99e7ee5e6bc4f362e008bf917ab5049887"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment