Commit a81de910 authored by Matthew Slipper's avatar Matthew Slipper Committed by GitHub

Merge pull request #11503 from ethereum-optimism/inphi/audit-fixes

Fault Proof Fixes
parents 2a995793 3a5e07f1
......@@ -153,7 +153,8 @@ func ExecuteMipsInstruction(insn, opcode, fun, rs, rt, mem uint32) uint32 {
case 0x06: // srlv
return rt >> (rs & 0x1F)
case 0x07: // srav
return SignExtend(rt>>rs, 32-rs)
shamt := rs & 0x1F
return SignExtend(rt>>shamt, 32-shamt)
// functs in range [0x8, 0x1b] are handled specially by other functions
case 0x08: // jr
return rs
......
......@@ -9,6 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/cannon/mipsevm"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/memory"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/program"
)
// Syscall codes
......@@ -132,7 +133,6 @@ const (
// Other constants
const (
SchedQuantum = 100_000
BrkStart = 0x40000000
)
func GetSyscallArgs(registers *[32]uint32) (syscallNum, a0, a1, a2, a3 uint32) {
......@@ -158,6 +158,12 @@ func HandleSysMmap(a0, a1, heap uint32) (v0, v1, newHeap uint32) {
v0 = heap
//fmt.Printf("mmap heap 0x%x size 0x%x\n", v0, sz)
newHeap += sz
// Fail if new heap exceeds memory limit, newHeap overflows around to low memory, or sz overflows
if newHeap > program.HEAP_END || newHeap < heap || sz < a1 {
v0 = SysErrorSignal
v1 = MipsEINVAL
return v0, v1, heap
}
} else {
v0 = a0
//fmt.Printf("mmap hint 0x%x size 0x%x\n", v0, sz)
......
......@@ -10,6 +10,7 @@ import (
"github.com/ethereum-optimism/optimism/cannon/mipsevm"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/exec"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/program"
)
func (m *InstrumentedState) handleSyscall() error {
......@@ -26,7 +27,7 @@ func (m *InstrumentedState) handleSyscall() error {
v0, v1, newHeap = exec.HandleSysMmap(a0, a1, m.state.Heap)
m.state.Heap = newHeap
case exec.SysBrk:
v0 = exec.BrkStart
v0 = program.PROGRAM_BREAK
case exec.SysClone: // clone
// a0 = flag bitmask, a1 = stack pointer
if exec.ValidCloneFlags != a0 {
......
......@@ -9,7 +9,11 @@ import (
"github.com/ethereum-optimism/optimism/cannon/mipsevm"
)
const HEAP_START = 0x05000000
const (
HEAP_START = 0x05_00_00_00
HEAP_END = 0x60_00_00_00
PROGRAM_BREAK = 0x40_00_00_00
)
type CreateInitialFPVMState[T mipsevm.FPVMState] func(pc, heapStart uint32) T
......
......@@ -5,6 +5,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/exec"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/program"
)
func (m *InstrumentedState) handleSyscall() error {
......@@ -20,7 +21,7 @@ func (m *InstrumentedState) handleSyscall() error {
v0, v1, newHeap = exec.HandleSysMmap(a0, a1, m.state.Heap)
m.state.Heap = newHeap
case exec.SysBrk:
v0 = exec.BrkStart
v0 = program.PROGRAM_BREAK
case exec.SysClone: // clone (not supported)
v0 = 1
case exec.SysExitGroup:
......
......@@ -5,6 +5,7 @@ import (
"io"
"os"
"path"
"strings"
"testing"
"time"
......@@ -18,6 +19,7 @@ import (
"github.com/ethereum-optimism/optimism/cannon/mipsevm/exec"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/memory"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/multithreaded"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/program"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/singlethreaded"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/testutil"
)
......@@ -48,6 +50,7 @@ func TestEVM(t *testing.T) {
oracle := testutil.SelectOracleFixture(t, f.Name())
// Short-circuit early for exit_group.bin
exitGroup := f.Name() == "exit_group.bin"
expectPanic := strings.HasSuffix(f.Name(), "panic.bin")
evm := testutil.NewMIPSEVM(contracts, addrs)
evm.SetTracer(tracer)
......@@ -66,6 +69,17 @@ func TestEVM(t *testing.T) {
goState := singlethreaded.NewInstrumentedState(state, oracle, os.Stdout, os.Stderr, nil)
// Catch panics and check if they are expected
defer func() {
if r := recover(); r != nil {
if expectPanic {
// Success
} else {
t.Errorf("unexpected panic: %v", r)
}
}
}()
for i := 0; i < 1000; i++ {
curStep := goState.GetState().GetStep()
if goState.GetState().GetPC() == testutil.EndAddr {
......@@ -90,6 +104,8 @@ func TestEVM(t *testing.T) {
require.NotEqual(t, uint32(testutil.EndAddr), goState.GetState().GetPC(), "must not reach end")
require.True(t, goState.GetState().GetExited(), "must set exited state")
require.Equal(t, uint8(1), goState.GetState().GetExitCode(), "must exit with 1")
} else if expectPanic {
require.NotEqual(t, uint32(testutil.EndAddr), goState.GetState().GetPC(), "must not reach end")
} else {
require.Equal(t, uint32(testutil.EndAddr), state.Cpu.PC, "must reach end")
// inspect test result
......@@ -193,6 +209,88 @@ func TestEVMSingleStep(t *testing.T) {
}
}
func TestEVM_MMap(t *testing.T) {
contracts, addrs := testContractsSetup(t)
var tracer *tracing.Hooks
cases := []struct {
name string
heap uint32
address uint32
size uint32
shouldFail bool
expectedHeap uint32
}{
{name: "Increment heap by max value", heap: program.HEAP_START, address: 0, size: ^uint32(0), shouldFail: true},
{name: "Increment heap to 0", heap: program.HEAP_START, address: 0, size: ^uint32(0) - program.HEAP_START + 1, shouldFail: true},
{name: "Increment heap to previous page", heap: program.HEAP_START, address: 0, size: ^uint32(0) - program.HEAP_START - memory.PageSize + 1, shouldFail: true},
{name: "Increment max page size", heap: program.HEAP_START, address: 0, size: ^uint32(0) & ^uint32(memory.PageAddrMask), shouldFail: true},
{name: "Increment max page size from 0", heap: 0, address: 0, size: ^uint32(0) & ^uint32(memory.PageAddrMask), shouldFail: true},
{name: "Increment heap at limit", heap: program.HEAP_END, address: 0, size: 1, shouldFail: true},
{name: "Increment heap to limit", heap: program.HEAP_END - memory.PageSize, address: 0, size: 1, shouldFail: false, expectedHeap: program.HEAP_END},
{name: "Increment heap within limit", heap: program.HEAP_END - 2*memory.PageSize, address: 0, size: 1, shouldFail: false, expectedHeap: program.HEAP_END - memory.PageSize},
{name: "Request specific address", heap: program.HEAP_START, address: 0x50_00_00_00, size: 0, shouldFail: false, expectedHeap: program.HEAP_START},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
state := singlethreaded.CreateEmptyState()
state.Heap = c.heap
state.Memory.SetMemory(state.GetPC(), syscallInsn)
state.Registers = testutil.RandomRegisters(77)
state.Registers[2] = exec.SysMmap
state.Registers[4] = c.address
state.Registers[5] = c.size
step := state.Step
expectedRegisters := state.Registers
expectedHeap := state.Heap
expectedMemoryRoot := state.Memory.MerkleRoot()
if c.shouldFail {
expectedRegisters[2] = exec.SysErrorSignal
expectedRegisters[7] = exec.MipsEINVAL
} else {
expectedHeap = c.expectedHeap
if c.address == 0 {
expectedRegisters[2] = state.Heap
expectedRegisters[7] = 0
} else {
expectedRegisters[2] = c.address
expectedRegisters[7] = 0
}
}
us := singlethreaded.NewInstrumentedState(state, nil, os.Stdout, os.Stderr, nil)
stepWitness, err := us.Step(true)
require.NoError(t, err)
// Check expectations
require.Equal(t, step+1, state.Step)
require.Equal(t, expectedHeap, state.Heap)
require.Equal(t, expectedRegisters, state.Registers)
require.Equal(t, expectedMemoryRoot, state.Memory.MerkleRoot())
require.Equal(t, common.Hash{}, state.PreimageKey)
require.Equal(t, uint32(0), state.PreimageOffset)
require.Equal(t, uint32(4), state.Cpu.PC)
require.Equal(t, uint32(8), state.Cpu.NextPC)
require.Equal(t, uint32(0), state.Cpu.HI)
require.Equal(t, uint32(0), state.Cpu.LO)
require.Equal(t, false, state.Exited)
require.Equal(t, uint8(0), state.ExitCode)
require.Equal(t, hexutil.Bytes(nil), state.LastHint)
evm := testutil.NewMIPSEVM(contracts, addrs)
evm.SetTracer(tracer)
testutil.LogStepFailureAtCleanup(t, evm)
evmPost := evm.Step(t, stepWitness, step, singlethreaded.GetStateHashFn())
goPost, _ := us.GetState().EncodeWitness()
require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM")
})
}
}
func TestEVMSysWriteHint(t *testing.T) {
contracts, addrs := testContractsSetup(t)
var tracer *tracing.Hooks
......
......@@ -14,6 +14,7 @@ import (
"github.com/ethereum-optimism/optimism/cannon/mipsevm"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/exec"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/memory"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/program"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/singlethreaded"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/testutil"
preimage "github.com/ethereum-optimism/optimism/op-preimage"
......@@ -45,7 +46,7 @@ func FuzzStateSyscallBrk(f *testing.F) {
state.Memory.SetMemory(pc, syscallInsn)
preStateRoot := state.Memory.MerkleRoot()
expectedRegisters := state.Registers
expectedRegisters[2] = 0x4000_0000
expectedRegisters[2] = program.PROGRAM_BREAK
goState := singlethreaded.NewInstrumentedState(state, nil, os.Stdout, os.Stderr, nil)
stepWitness, err := goState.Step(true)
......@@ -127,7 +128,14 @@ func FuzzStateSyscallClone(f *testing.F) {
func FuzzStateSyscallMmap(f *testing.F) {
contracts, addrs := testContractsSetup(f)
step := uint64(0)
f.Fuzz(func(t *testing.T, addr uint32, siz uint32, heap uint32) {
// Add special cases for large memory allocation
f.Add(uint32(0), uint32(0x1000), uint32(program.HEAP_END), int64(1))
f.Add(uint32(0), uint32(1<<31), uint32(program.HEAP_START), int64(2))
// Check edge case - just within bounds
f.Add(uint32(0), uint32(0x1000), uint32(program.HEAP_END-4096), int64(3))
f.Fuzz(func(t *testing.T, addr uint32, siz uint32, heap uint32, seed int64) {
state := &singlethreaded.State{
Cpu: mipsevm.CpuScalars{
PC: 0,
......@@ -139,11 +147,14 @@ func FuzzStateSyscallMmap(f *testing.F) {
ExitCode: 0,
Exited: false,
Memory: memory.NewMemory(),
Registers: [32]uint32{2: exec.SysMmap, 4: addr, 5: siz},
Registers: testutil.RandomRegisters(seed),
Step: step,
PreimageOffset: 0,
}
state.Memory.SetMemory(0, syscallInsn)
state.Registers[2] = exec.SysMmap
state.Registers[4] = addr
state.Registers[5] = siz
preStateRoot := state.Memory.MerkleRoot()
preStateRegisters := state.Registers
......@@ -152,32 +163,42 @@ func FuzzStateSyscallMmap(f *testing.F) {
require.NoError(t, err)
require.False(t, stepWitness.HasPreimage())
require.Equal(t, uint32(4), state.Cpu.PC)
require.Equal(t, uint32(8), state.Cpu.NextPC)
require.Equal(t, uint32(0), state.Cpu.LO)
require.Equal(t, uint32(0), state.Cpu.HI)
require.Equal(t, uint8(0), state.ExitCode)
require.Equal(t, false, state.Exited)
require.Equal(t, preStateRoot, state.Memory.MerkleRoot())
require.Equal(t, uint64(1), state.Step)
require.Equal(t, common.Hash{}, state.PreimageKey)
require.Equal(t, uint32(0), state.PreimageOffset)
var expectedHeap uint32
expectedRegisters := preStateRegisters
if addr == 0 {
expectedRegisters := preStateRegisters
expectedRegisters[2] = heap
require.Equal(t, expectedRegisters, state.Registers)
sizAlign := siz
if sizAlign&memory.PageAddrMask != 0 { // adjust size to align with page size
sizAlign = siz + memory.PageSize - (siz & memory.PageAddrMask)
}
require.Equal(t, uint32(heap+sizAlign), state.Heap)
newHeap := heap + sizAlign
if newHeap > program.HEAP_END || newHeap < heap || sizAlign < siz {
expectedHeap = heap
expectedRegisters[2] = exec.SysErrorSignal
expectedRegisters[7] = exec.MipsEINVAL
} else {
expectedRegisters[2] = heap
expectedRegisters[7] = 0 // no error
expectedHeap = heap + sizAlign
}
} else {
expectedRegisters := preStateRegisters
expectedRegisters[2] = addr
require.Equal(t, expectedRegisters, state.Registers)
require.Equal(t, uint32(heap), state.Heap)
expectedRegisters[7] = 0 // no error
expectedHeap = heap
}
require.Equal(t, uint32(4), state.Cpu.PC)
require.Equal(t, uint32(8), state.Cpu.NextPC)
require.Equal(t, uint32(0), state.Cpu.LO)
require.Equal(t, uint32(0), state.Cpu.HI)
require.Equal(t, preStateRoot, state.Memory.MerkleRoot())
require.Equal(t, uint64(1), state.Step)
require.Equal(t, common.Hash{}, state.PreimageKey)
require.Equal(t, uint32(0), state.PreimageOffset)
require.Equal(t, expectedHeap, state.Heap)
require.Equal(t, uint8(0), state.ExitCode)
require.Equal(t, false, state.Exited)
require.Equal(t, expectedRegisters, state.Registers)
evm := testutil.NewMIPSEVM(contracts, addrs)
evmPost := evm.Step(t, stepWitness, step, singlethreaded.GetStateHashFn())
goPost, _ := goState.GetState().EncodeWitness()
......
......@@ -5,36 +5,37 @@
.ent test
# load hash at 0x30001000
# point evaluation precompile input - 01e798154708fe7789429634053cbf9f99b619f9f084048927333fce637f549b564c0a11a0f704f4fc3e8acfe0f8245f0ad1347b378fbf96e206da11a5d3630624d25032e67a7e6a4910df5834b8fe70e6bcfeeac0352434196bdf4b2485d5a18f59a8d2a1a625a17f3fea0fe5eb8c896db3764f3185481bc22f91b4aaffcca25f26936857bc3a7c2539ea8ec3a952b7873033e038326e87ed3e1276fd140253fa08e9fc25fb2d9a98527fc22a2c9612fbeafdad446cbc7bcdbdcd780af2c16a
# 0x0a44472c cb798bc5 954fc466 e6ee2c31 e1ca8a87 d000966c 629d679a 4a29921f = keccak(address(0xa) ++ precompile_input)
# 0x0644472c cb798bc5 954fc466 e6ee2c31 e1ca8a87 d000966c 629d679a 4a29921f = keccak(address(0xa) ++ precompile_input).key (precompile)
# requiredGas is 50_000
# point evaluation precompile input (requiredGas ++ precompileInput) - 000000000000c35001e798154708fe7789429634053cbf9f99b619f9f084048927333fce637f549b564c0a11a0f704f4fc3e8acfe0f8245f0ad1347b378fbf96e206da11a5d3630624d25032e67a7e6a4910df5834b8fe70e6bcfeeac0352434196bdf4b2485d5a18f59a8d2a1a625a17f3fea0fe5eb8c896db3764f3185481bc22f91b4aaffcca25f26936857bc3a7c2539ea8ec3a952b7873033e038326e87ed3e1276fd140253fa08e9fc25fb2d9a98527fc22a2c9612fbeafdad446cbc7bcdbdcd780af2c16a
# 0x3efd5c3c 1c555298 0c63aee5 4570c276 cbff7532 796b4d75 3132d51a 6bedf0c6 = keccak(address(0xa) ++ required_gas ++ precompile_input)
# 0x06fd5c3c 1c555298 0c63aee5 4570c276 cbff7532 796b4d75 3132d51a 6bedf0c6 = keccak(address(0xa) ++ required_gas ++ precompile_input).key (precompile)
test:
lui $s0, 0x3000
ori $s0, 0x1000
lui $t0, 0x0644
ori $t0, 0x472c
lui $t0, 0x06fd
ori $t0, 0x5c3c
sw $t0, 0($s0)
lui $t0, 0xcb79
ori $t0, 0x8bc5
lui $t0, 0x1c55
ori $t0, 0x5298
sw $t0, 4($s0)
lui $t0, 0x954f
ori $t0, 0xc466
lui $t0, 0x0c63
ori $t0, 0xaee5
sw $t0, 8($s0)
lui $t0, 0xe6ee
ori $t0, 0x2c31
lui $t0, 0x4570
ori $t0, 0xc276
sw $t0, 0xc($s0)
lui $t0, 0xe1ca
ori $t0, 0x8a87
lui $t0, 0xcbff
ori $t0, 0x7532
sw $t0, 0x10($s0)
lui $t0, 0xd000
ori $t0, 0x966c
lui $t0, 0x796b
ori $t0, 0x4d75
sw $t0, 0x14($s0)
lui $t0, 0x629d
ori $t0, 0x679a
lui $t0, 0x3132
ori $t0, 0xd51a
sw $t0, 0x18($s0)
lui $t0, 0x4a29
ori $t0, 0x921f
lui $t0, 0x6bed
ori $t0, 0xf0c6
sw $t0, 0x1c($s0)
# preimage request - write(fdPreimageWrite, preimageData, 32)
......
###############################################################################
# Description:
# Tests that the 'srav' instruction properly only utilizes the lower 5 bits
# of the rs register rather than using the entire 32 bits.
#
###############################################################################
.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, 0x2c
srav $t2, $t0, $t1 # B = 0xdeafbeef >> (0x2c & 0x1f) = 0xdeadbeef >> 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
package testutil
import (
"encoding/binary"
"errors"
"fmt"
"math"
......@@ -121,11 +122,13 @@ func EncodePreimageOracleInput(t *testing.T, wit *mipsevm.StepWitness, localCont
}
preimage := localOracle.GetPreimage(preimage.Keccak256Key(wit.PreimageKey).PreimageKey())
precompile := common.BytesToAddress(preimage[:20])
callInput := preimage[20:]
requiredGas := binary.BigEndian.Uint64(preimage[20:28])
callInput := preimage[28:]
input, err := oracle.ABI.Pack(
"loadPrecompilePreimagePart",
new(big.Int).SetUint64(uint64(wit.PreimageOffset)),
precompile,
requiredGas,
callInput,
)
require.NoError(t, err)
......
......@@ -42,11 +42,13 @@ func StaticOracle(t *testing.T, preimageData []byte) *TestOracle {
}
}
func StaticPrecompileOracle(t *testing.T, precompile common.Address, input []byte, result []byte) *TestOracle {
func StaticPrecompileOracle(t *testing.T, precompile common.Address, requiredGas uint64, input []byte, result []byte) *TestOracle {
return &TestOracle{
hint: func(v []byte) {},
getPreimage: func(k [32]byte) []byte {
keyData := append(precompile.Bytes(), input...)
requiredGasB := binary.BigEndian.AppendUint64(nil, requiredGas)
keyData := append(precompile.Bytes(), requiredGasB...)
keyData = append(keyData, input...)
switch k[0] {
case byte(preimage.Keccak256KeyType):
if k != preimage.Keccak256Key(crypto.Keccak256Hash(keyData)).PreimageKey() {
......@@ -135,7 +137,8 @@ func SelectOracleFixture(t *testing.T, programName string) mipsevm.PreimageOracl
precompile := common.BytesToAddress([]byte{0xa})
input := common.FromHex("01e798154708fe7789429634053cbf9f99b619f9f084048927333fce637f549b564c0a11a0f704f4fc3e8acfe0f8245f0ad1347b378fbf96e206da11a5d3630624d25032e67a7e6a4910df5834b8fe70e6bcfeeac0352434196bdf4b2485d5a18f59a8d2a1a625a17f3fea0fe5eb8c896db3764f3185481bc22f91b4aaffcca25f26936857bc3a7c2539ea8ec3a952b7873033e038326e87ed3e1276fd140253fa08e9fc25fb2d9a98527fc22a2c9612fbeafdad446cbc7bcdbdcd780af2c16a")
blobPrecompileReturnValue := common.FromHex("000000000000000000000000000000000000000000000000000000000000100073eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001")
return StaticPrecompileOracle(t, precompile, input, append([]byte{0x1}, blobPrecompileReturnValue...))
requiredGas := uint64(50_000)
return StaticPrecompileOracle(t, precompile, requiredGas, input, append([]byte{0x1}, blobPrecompileReturnValue...))
} else if strings.HasPrefix(programName, "oracle") {
return StaticOracle(t, []byte("hello world"))
} else {
......
package testutil
import "math/rand"
func RandomRegisters(seed int64) [32]uint32 {
r := rand.New(rand.NewSource(seed))
var registers [32]uint32
for i := 0; i < 32; i++ {
registers[i] = r.Uint32()
}
return registers
}
......@@ -5,6 +5,7 @@ import (
"io"
"os"
"path"
"strings"
"testing"
"github.com/ethereum/go-ethereum/log"
......@@ -32,6 +33,7 @@ func RunVMTests_OpenMips[T mipsevm.FPVMState](t *testing.T, stateFactory StateFa
oracle := SelectOracleFixture(t, f.Name())
// Short-circuit early for exit_group.bin
exitGroup := f.Name() == "exit_group.bin"
expectPanic := strings.HasSuffix(f.Name(), "panic.bin")
// 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
......@@ -51,6 +53,17 @@ func RunVMTests_OpenMips[T mipsevm.FPVMState](t *testing.T, stateFactory StateFa
us := vmFactory(state, oracle, os.Stdout, os.Stderr, CreateLogger())
// Catch panics and check if they are expected
defer func() {
if r := recover(); r != nil {
if expectPanic {
// Success
} else {
t.Errorf("unexpected panic: %v", r)
}
}
}()
for i := 0; i < 1000; i++ {
if us.GetState().GetPC() == EndAddr {
break
......@@ -66,6 +79,8 @@ func RunVMTests_OpenMips[T mipsevm.FPVMState](t *testing.T, stateFactory StateFa
require.NotEqual(t, uint32(EndAddr), us.GetState().GetPC(), "must not reach end")
require.True(t, us.GetState().GetExited(), "must set exited state")
require.Equal(t, uint8(1), us.GetState().GetExitCode(), "must exit with 1")
} else if expectPanic {
require.NotEqual(t, uint32(EndAddr), us.GetState().GetPC(), "must not reach end")
} else {
require.Equal(t, uint32(EndAddr), us.GetState().GetPC(), "must reach end")
done, result := state.GetMemory().GetMemory(BaseAddrEnd+4), state.GetMemory().GetMemory(BaseAddrEnd+8)
......
[
{
"inputs": [
{
"internalType": "uint256",
"name": "_minProposalSize",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_challengePeriod",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "KECCAK_TREE_DEPTH",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_LEAF_COUNT",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MIN_BOND_SIZE",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_uuid",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_inputStartBlock",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "_input",
"type": "bytes"
},
{
"internalType": "bytes32[]",
"name": "_stateCommitments",
"type": "bytes32[]"
},
{
"internalType": "bool",
"name": "_finalize",
"type": "bool"
}
],
"name": "addLeavesLPP",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_claimant",
"type": "address"
},
{
"internalType": "uint256",
"name": "_uuid",
"type": "uint256"
},
{
"components": [
{
"internalType": "bytes",
"name": "input",
"type": "bytes"
},
{
"internalType": "uint256",
"name": "index",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "stateCommitment",
"type": "bytes32"
}
],
"internalType": "struct PreimageOracle.Leaf",
"name": "_postState",
"type": "tuple"
},
{
"internalType": "bytes32[]",
"name": "_postStateProof",
"type": "bytes32[]"
}
],
"name": "challengeFirstLPP",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_claimant",
"type": "address"
},
{
"internalType": "uint256",
"name": "_uuid",
"type": "uint256"
},
{
"components": [
{
"internalType": "uint64[25]",
"name": "state",
"type": "uint64[25]"
}
],
"internalType": "struct LibKeccak.StateMatrix",
"name": "_stateMatrix",
"type": "tuple"
},
{
"components": [
{
"internalType": "bytes",
"name": "input",
"type": "bytes"
},
{
"internalType": "uint256",
"name": "index",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "stateCommitment",
"type": "bytes32"
}
],
"internalType": "struct PreimageOracle.Leaf",
"name": "_preState",
"type": "tuple"
},
{
"internalType": "bytes32[]",
"name": "_preStateProof",
"type": "bytes32[]"
},
{
"components": [
{
"internalType": "bytes",
"name": "input",
"type": "bytes"
},
{
"internalType": "uint256",
"name": "index",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "stateCommitment",
"type": "bytes32"
}
],
"internalType": "struct PreimageOracle.Leaf",
"name": "_postState",
"type": "tuple"
},
{
"internalType": "bytes32[]",
"name": "_postStateProof",
"type": "bytes32[]"
}
],
"name": "challengeLPP",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "challengePeriod",
"outputs": [
{
"internalType": "uint256",
"name": "challengePeriod_",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_owner",
"type": "address"
},
{
"internalType": "uint256",
"name": "_uuid",
"type": "uint256"
}
],
"name": "getTreeRootLPP",
"outputs": [
{
"internalType": "bytes32",
"name": "treeRoot_",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_uuid",
"type": "uint256"
},
{
"internalType": "uint32",
"name": "_partOffset",
"type": "uint32"
},
{
"internalType": "uint32",
"name": "_claimedSize",
"type": "uint32"
}
],
"name": "initLPP",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_z",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_y",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "_commitment",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "_proof",
"type": "bytes"
},
{
"internalType": "uint256",
"name": "_partOffset",
"type": "uint256"
}
],
"name": "loadBlobPreimagePart",
"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": "uint256",
"name": "_ident",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "_localContext",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "_word",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "_size",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_partOffset",
"type": "uint256"
}
],
"name": "loadLocalData",
"outputs": [
{
"internalType": "bytes32",
"name": "key_",
"type": "bytes32"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_partOffset",
"type": "uint256"
},
{
"internalType": "address",
"name": "_precompile",
"type": "address"
},
{
"internalType": "bytes",
"name": "_input",
"type": "bytes"
}
],
"name": "loadPrecompilePreimagePart",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_partOffset",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "_preimage",
"type": "bytes"
}
],
"name": "loadSha256PreimagePart",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "minProposalSize",
"outputs": [
{
"internalType": "uint256",
"name": "minProposalSize_",
"type": "uint256"
}
],
"stateMutability": "view",
"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": "address",
"name": "",
"type": "address"
},
{
"internalType": "uint256",
"name": "",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "proposalBlocks",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_claimant",
"type": "address"
},
{
"internalType": "uint256",
"name": "_uuid",
"type": "uint256"
}
],
"name": "proposalBlocksLen",
"outputs": [
{
"internalType": "uint256",
"name": "len_",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "proposalBonds",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "uint256",
"name": "",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "proposalBranches",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "proposalCount",
"outputs": [
{
"internalType": "uint256",
"name": "count_",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "proposalMetadata",
"outputs": [
{
"internalType": "LPPMetaData",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "proposalParts",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "proposals",
"outputs": [
{
"internalType": "address",
"name": "claimant",
"type": "address"
},
{
"internalType": "uint256",
"name": "uuid",
"type": "uint256"
}
],
"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"
},
{
"inputs": [
{
"internalType": "address",
"name": "_claimant",
"type": "address"
},
{
"internalType": "uint256",
"name": "_uuid",
"type": "uint256"
},
{
"components": [
{
"internalType": "uint64[25]",
"name": "state",
"type": "uint64[25]"
}
],
"internalType": "struct LibKeccak.StateMatrix",
"name": "_stateMatrix",
"type": "tuple"
},
{
"components": [
{
"internalType": "bytes",
"name": "input",
"type": "bytes"
},
{
"internalType": "uint256",
"name": "index",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "stateCommitment",
"type": "bytes32"
}
],
"internalType": "struct PreimageOracle.Leaf",
"name": "_preState",
"type": "tuple"
},
{
"internalType": "bytes32[]",
"name": "_preStateProof",
"type": "bytes32[]"
},
{
"components": [
{
"internalType": "bytes",
"name": "input",
"type": "bytes"
},
{
"internalType": "uint256",
"name": "index",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "stateCommitment",
"type": "bytes32"
}
],
"internalType": "struct PreimageOracle.Leaf",
"name": "_postState",
"type": "tuple"
},
{
"internalType": "bytes32[]",
"name": "_postStateProof",
"type": "bytes32[]"
}
],
"name": "squeezeLPP",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "version",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "zeroHashes",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "ActiveProposal",
"type": "error"
},
{
"inputs": [],
"name": "AlreadyFinalized",
"type": "error"
},
{
"inputs": [],
"name": "BadProposal",
"type": "error"
},
{
"inputs": [],
"name": "BondTransferFailed",
"type": "error"
},
{
"inputs": [],
"name": "InsufficientBond",
"type": "error"
},
{
"inputs": [],
"name": "InvalidInputSize",
"type": "error"
},
{
"inputs": [],
"name": "InvalidPreimage",
"type": "error"
},
{
"inputs": [],
"name": "InvalidProof",
"type": "error"
},
{
"inputs": [],
"name": "NotEOA",
"type": "error"
},
{
"inputs": [],
"name": "NotInitialized",
"type": "error"
},
{
"inputs": [],
"name": "PartOffsetOOB",
"type": "error"
},
{
"inputs": [],
"name": "PostStateMatches",
"type": "error"
},
{
"inputs": [],
"name": "StatesNotContiguous",
"type": "error"
},
{
"inputs": [],
"name": "TreeSizeOverflow",
"type": "error"
},
{
"inputs": [],
"name": "WrongStartingBlock",
"type": "error"
}
]
\ No newline at end of file
......@@ -7,7 +7,6 @@ import (
"fmt"
"math"
"math/big"
"strings"
"time"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
......@@ -26,7 +25,6 @@ import (
var maxChildChecks = big.NewInt(512)
var (
methodVersion = "version"
methodMaxClockDuration = "maxClockDuration"
methodMaxGameDepth = "maxGameDepth"
methodAbsolutePrestate = "absolutePrestate"
......@@ -84,14 +82,8 @@ type outputRootProof struct {
func NewFaultDisputeGameContract(ctx context.Context, metrics metrics.ContractMetricer, addr common.Address, caller *batching.MultiCaller) (FaultDisputeGameContract, error) {
contractAbi := snapshots.LoadFaultDisputeGameABI()
result, err := caller.SingleCall(ctx, rpcblock.Latest, batching.NewContractCall(contractAbi, addr, methodVersion))
if err != nil {
return nil, fmt.Errorf("failed to retrieve version of dispute game %v: %w", addr, err)
}
version := result.GetString(0)
if strings.HasPrefix(version, "0.8.") {
// Detected an older version of contracts, use a compatibility shim.
var builder VersionedBuilder[FaultDisputeGameContract]
builder.AddVersion(0, 8, func() (FaultDisputeGameContract, error) {
legacyAbi := mustParseAbi(faultDisputeGameAbi020)
return &FaultDisputeGameContract080{
FaultDisputeGameContractLatest: FaultDisputeGameContractLatest{
......@@ -100,8 +92,8 @@ func NewFaultDisputeGameContract(ctx context.Context, metrics metrics.ContractMe
contract: batching.NewBoundContract(legacyAbi, addr),
},
}, nil
} else if strings.HasPrefix(version, "0.18.") || strings.HasPrefix(version, "1.0.") {
// Detected an older version of contracts, use a compatibility shim.
})
builder.AddVersion(0, 18, func() (FaultDisputeGameContract, error) {
legacyAbi := mustParseAbi(faultDisputeGameAbi0180)
return &FaultDisputeGameContract0180{
FaultDisputeGameContractLatest: FaultDisputeGameContractLatest{
......@@ -110,8 +102,18 @@ func NewFaultDisputeGameContract(ctx context.Context, metrics metrics.ContractMe
contract: batching.NewBoundContract(legacyAbi, addr),
},
}, nil
} else if strings.HasPrefix(version, "1.1.") {
// Detected an older version of contracts, use a compatibility shim.
})
builder.AddVersion(1, 0, func() (FaultDisputeGameContract, error) {
legacyAbi := mustParseAbi(faultDisputeGameAbi0180)
return &FaultDisputeGameContract0180{
FaultDisputeGameContractLatest: FaultDisputeGameContractLatest{
metrics: metrics,
multiCaller: caller,
contract: batching.NewBoundContract(legacyAbi, addr),
},
}, nil
})
builder.AddVersion(1, 1, func() (FaultDisputeGameContract, error) {
legacyAbi := mustParseAbi(faultDisputeGameAbi111)
return &FaultDisputeGameContract111{
FaultDisputeGameContractLatest: FaultDisputeGameContractLatest{
......@@ -120,13 +122,14 @@ func NewFaultDisputeGameContract(ctx context.Context, metrics metrics.ContractMe
contract: batching.NewBoundContract(legacyAbi, addr),
},
}, nil
} else {
})
return builder.Build(ctx, caller, contractAbi, addr, func() (FaultDisputeGameContract, error) {
return &FaultDisputeGameContractLatest{
metrics: metrics,
multiCaller: caller,
contract: batching.NewBoundContract(contractAbi, addr),
}, nil
}
})
}
func mustParseAbi(json []byte) *abi.ABI {
......@@ -364,7 +367,7 @@ func (f *FaultDisputeGameContractLatest) getDelayedWETH(ctx context.Context, blo
return NewDelayedWETHContract(f.metrics, result.GetAddress(0), f.multiCaller), nil
}
func (f *FaultDisputeGameContractLatest) GetOracle(ctx context.Context) (*PreimageOracleContract, error) {
func (f *FaultDisputeGameContractLatest) GetOracle(ctx context.Context) (PreimageOracleContract, error) {
defer f.metrics.StartContractRequest("GetOracle")()
vm, err := f.Vm(ctx)
if err != nil {
......@@ -616,7 +619,7 @@ type FaultDisputeGameContract interface {
GetRequiredBond(ctx context.Context, position types.Position) (*big.Int, error)
UpdateOracleTx(ctx context.Context, claimIdx uint64, data *types.PreimageOracleData) (txmgr.TxCandidate, error)
GetWithdrawals(ctx context.Context, block rpcblock.Block, recipients ...common.Address) ([]*WithdrawalRequest, error)
GetOracle(ctx context.Context) (*PreimageOracleContract, error)
GetOracle(ctx context.Context) (PreimageOracleContract, error)
GetMaxClockDuration(ctx context.Context) (time.Duration, error)
GetMaxGameDepth(ctx context.Context) (types.Depth, error)
GetAbsolutePrestateHash(ctx context.Context) (common.Hash, error)
......
......@@ -797,6 +797,7 @@ func setupFaultDisputeGameTest(t *testing.T, version contractVersion) (*batching
caller := batching.NewMultiCaller(stubRpc, batching.DefaultBatchSize)
stubRpc.SetResponse(fdgAddr, methodVersion, rpcblock.Latest, nil, []interface{}{version.version})
stubRpc.SetResponse(oracleAddr, methodVersion, rpcblock.Latest, nil, []interface{}{oracleLatest})
game, err := NewFaultDisputeGameContract(context.Background(), contractMetrics.NoopContractMetrics, fdgAddr, caller)
require.NoError(t, err)
return stubRpc, game
......
......@@ -60,8 +60,8 @@ type libKeccakStateMatrix struct {
State [25]uint64
}
// PreimageOracleContract is a binding that works with contracts implementing the IPreimageOracle interface
type PreimageOracleContract struct {
// PreimageOracleContractLatest is a binding that works with contracts implementing the IPreimageOracle interface
type PreimageOracleContractLatest struct {
addr common.Address
multiCaller *batching.MultiCaller
contract *batching.BoundContract
......@@ -83,21 +83,36 @@ func toPreimageOracleLeaf(l keccakTypes.Leaf) preimageOracleLeaf {
}
}
func NewPreimageOracleContract(addr common.Address, caller *batching.MultiCaller) *PreimageOracleContract {
func NewPreimageOracleContract(ctx context.Context, addr common.Address, caller *batching.MultiCaller) (PreimageOracleContract, error) {
oracleAbi := snapshots.LoadPreimageOracleABI()
return &PreimageOracleContract{
addr: addr,
multiCaller: caller,
contract: batching.NewBoundContract(oracleAbi, addr),
}
var builder VersionedBuilder[PreimageOracleContract]
builder.AddVersion(1, 0, func() (PreimageOracleContract, error) {
legacyAbi := mustParseAbi(preimageOracleAbi100)
return &PreimageOracleContract100{
PreimageOracleContractLatest{
addr: addr,
multiCaller: caller,
contract: batching.NewBoundContract(legacyAbi, addr),
},
}, nil
})
return builder.Build(ctx, caller, oracleAbi, addr, func() (PreimageOracleContract, error) {
return &PreimageOracleContractLatest{
addr: addr,
multiCaller: caller,
contract: batching.NewBoundContract(oracleAbi, addr),
}, nil
})
}
func (c *PreimageOracleContract) Addr() common.Address {
func (c *PreimageOracleContractLatest) Addr() common.Address {
return c.addr
}
func (c *PreimageOracleContract) AddGlobalDataTx(data *types.PreimageOracleData) (txmgr.TxCandidate, error) {
func (c *PreimageOracleContractLatest) AddGlobalDataTx(data *types.PreimageOracleData) (txmgr.TxCandidate, error) {
if len(data.OracleKey) == 0 {
return txmgr.TxCandidate{}, ErrInvalidPreimageKey
}
......@@ -121,6 +136,7 @@ func (c *PreimageOracleContract) AddGlobalDataTx(data *types.PreimageOracleData)
call := c.contract.Call(methodLoadPrecompilePreimagePart,
new(big.Int).SetUint64(uint64(data.OracleOffset)),
data.GetPrecompileAddress(),
data.GetPrecompileRequiredGas(),
data.GetPrecompileInput())
return call.ToTxCandidate()
default:
......@@ -128,7 +144,7 @@ func (c *PreimageOracleContract) AddGlobalDataTx(data *types.PreimageOracleData)
}
}
func (c *PreimageOracleContract) InitLargePreimage(uuid *big.Int, partOffset uint32, claimedSize uint32) (txmgr.TxCandidate, error) {
func (c *PreimageOracleContractLatest) InitLargePreimage(uuid *big.Int, partOffset uint32, claimedSize uint32) (txmgr.TxCandidate, error) {
bond, err := c.GetMinBondLPP(context.Background())
if err != nil {
return txmgr.TxCandidate{}, fmt.Errorf("failed to get min bond for large preimage proposal: %w", err)
......@@ -142,13 +158,13 @@ func (c *PreimageOracleContract) InitLargePreimage(uuid *big.Int, partOffset uin
return candidate, nil
}
func (c *PreimageOracleContract) AddLeaves(uuid *big.Int, startingBlockIndex *big.Int, input []byte, commitments []common.Hash, finalize bool) (txmgr.TxCandidate, error) {
func (c *PreimageOracleContractLatest) AddLeaves(uuid *big.Int, startingBlockIndex *big.Int, input []byte, commitments []common.Hash, finalize bool) (txmgr.TxCandidate, error) {
call := c.contract.Call(methodAddLeavesLPP, uuid, startingBlockIndex, input, commitments, finalize)
return call.ToTxCandidate()
}
// MinLargePreimageSize returns the minimum size of a large preimage.
func (c *PreimageOracleContract) MinLargePreimageSize(ctx context.Context) (uint64, error) {
func (c *PreimageOracleContractLatest) MinLargePreimageSize(ctx context.Context) (uint64, error) {
result, err := c.multiCaller.SingleCall(ctx, rpcblock.Latest, c.contract.Call(methodMinProposalSize))
if err != nil {
return 0, fmt.Errorf("failed to fetch min lpp size bytes: %w", err)
......@@ -157,7 +173,7 @@ func (c *PreimageOracleContract) MinLargePreimageSize(ctx context.Context) (uint
}
// ChallengePeriod returns the challenge period for large preimages.
func (c *PreimageOracleContract) ChallengePeriod(ctx context.Context) (uint64, error) {
func (c *PreimageOracleContractLatest) ChallengePeriod(ctx context.Context) (uint64, error) {
if period := c.challengePeriod.Load(); period != 0 {
return period, nil
}
......@@ -170,7 +186,7 @@ func (c *PreimageOracleContract) ChallengePeriod(ctx context.Context) (uint64, e
return period, nil
}
func (c *PreimageOracleContract) CallSqueeze(
func (c *PreimageOracleContractLatest) CallSqueeze(
ctx context.Context,
claimant common.Address,
uuid *big.Int,
......@@ -188,7 +204,7 @@ func (c *PreimageOracleContract) CallSqueeze(
return nil
}
func (c *PreimageOracleContract) Squeeze(
func (c *PreimageOracleContractLatest) Squeeze(
claimant common.Address,
uuid *big.Int,
prestateMatrix keccakTypes.StateSnapshot,
......@@ -214,7 +230,7 @@ func abiEncodeSnapshot(packedState keccakTypes.StateSnapshot) libKeccakStateMatr
return libKeccakStateMatrix{State: packedState}
}
func (c *PreimageOracleContract) GetActivePreimages(ctx context.Context, blockHash common.Hash) ([]keccakTypes.LargePreimageMetaData, error) {
func (c *PreimageOracleContractLatest) GetActivePreimages(ctx context.Context, blockHash common.Hash) ([]keccakTypes.LargePreimageMetaData, error) {
block := rpcblock.ByHash(blockHash)
results, err := batching.ReadArray(ctx, c.multiCaller, block, c.contract.Call(methodProposalCount), func(i *big.Int) *batching.ContractCall {
return c.contract.Call(methodProposals, i)
......@@ -231,7 +247,7 @@ func (c *PreimageOracleContract) GetActivePreimages(ctx context.Context, blockHa
return c.GetProposalMetadata(ctx, block, idents...)
}
func (c *PreimageOracleContract) GetProposalMetadata(ctx context.Context, block rpcblock.Block, idents ...keccakTypes.LargePreimageIdent) ([]keccakTypes.LargePreimageMetaData, error) {
func (c *PreimageOracleContractLatest) GetProposalMetadata(ctx context.Context, block rpcblock.Block, idents ...keccakTypes.LargePreimageIdent) ([]keccakTypes.LargePreimageMetaData, error) {
var calls []batching.Call
for _, ident := range idents {
calls = append(calls, c.contract.Call(methodProposalMetadata, ident.Claimant, ident.UUID))
......@@ -256,7 +272,7 @@ func (c *PreimageOracleContract) GetProposalMetadata(ctx context.Context, block
return proposals, nil
}
func (c *PreimageOracleContract) GetProposalTreeRoot(ctx context.Context, block rpcblock.Block, ident keccakTypes.LargePreimageIdent) (common.Hash, error) {
func (c *PreimageOracleContractLatest) GetProposalTreeRoot(ctx context.Context, block rpcblock.Block, ident keccakTypes.LargePreimageIdent) (common.Hash, error) {
call := c.contract.Call(methodGetTreeRootLPP, ident.Claimant, ident.UUID)
result, err := c.multiCaller.SingleCall(ctx, block, call)
if err != nil {
......@@ -265,7 +281,7 @@ func (c *PreimageOracleContract) GetProposalTreeRoot(ctx context.Context, block
return result.GetHash(0), nil
}
func (c *PreimageOracleContract) GetInputDataBlocks(ctx context.Context, block rpcblock.Block, ident keccakTypes.LargePreimageIdent) ([]uint64, error) {
func (c *PreimageOracleContractLatest) GetInputDataBlocks(ctx context.Context, block rpcblock.Block, ident keccakTypes.LargePreimageIdent) ([]uint64, error) {
results, err := batching.ReadArray(ctx, c.multiCaller, block,
c.contract.Call(methodProposalBlocksLen, ident.Claimant, ident.UUID),
func(i *big.Int) *batching.ContractCall {
......@@ -285,7 +301,7 @@ func (c *PreimageOracleContract) GetInputDataBlocks(ctx context.Context, block r
// An [ErrInvalidAddLeavesCall] error is returned if the call is not a valid call to addLeavesLPP.
// Otherwise, the uuid and input data is returned. The raw data supplied is returned so long as it can be parsed.
// Specifically the length of the input data is not validated to ensure it is consistent with the number of commitments.
func (c *PreimageOracleContract) DecodeInputData(data []byte) (*big.Int, keccakTypes.InputData, error) {
func (c *PreimageOracleContractLatest) DecodeInputData(data []byte) (*big.Int, keccakTypes.InputData, error) {
method, args, err := c.contract.DecodeCall(data)
if errors.Is(err, batching.ErrUnknownMethod) {
return nil, keccakTypes.InputData{}, ErrInvalidAddLeavesCall
......@@ -312,7 +328,7 @@ func (c *PreimageOracleContract) DecodeInputData(data []byte) (*big.Int, keccakT
}, nil
}
func (c *PreimageOracleContract) GlobalDataExists(ctx context.Context, data *types.PreimageOracleData) (bool, error) {
func (c *PreimageOracleContractLatest) GlobalDataExists(ctx context.Context, data *types.PreimageOracleData) (bool, error) {
call := c.contract.Call(methodPreimagePartOk, common.Hash(data.OracleKey), new(big.Int).SetUint64(uint64(data.OracleOffset)))
results, err := c.multiCaller.SingleCall(ctx, rpcblock.Latest, call)
if err != nil {
......@@ -321,7 +337,7 @@ func (c *PreimageOracleContract) GlobalDataExists(ctx context.Context, data *typ
return results.GetBool(0), nil
}
func (c *PreimageOracleContract) ChallengeTx(ident keccakTypes.LargePreimageIdent, challenge keccakTypes.Challenge) (txmgr.TxCandidate, error) {
func (c *PreimageOracleContractLatest) ChallengeTx(ident keccakTypes.LargePreimageIdent, challenge keccakTypes.Challenge) (txmgr.TxCandidate, error) {
var call *batching.ContractCall
if challenge.Prestate == (keccakTypes.Leaf{}) {
call = c.contract.Call(
......@@ -344,7 +360,7 @@ func (c *PreimageOracleContract) ChallengeTx(ident keccakTypes.LargePreimageIden
return call.ToTxCandidate()
}
func (c *PreimageOracleContract) GetMinBondLPP(ctx context.Context) (*big.Int, error) {
func (c *PreimageOracleContractLatest) GetMinBondLPP(ctx context.Context) (*big.Int, error) {
if bondSize := c.minBondSizeLPP.Load(); bondSize != 0 {
return big.NewInt(int64(bondSize)), nil
}
......@@ -357,7 +373,7 @@ func (c *PreimageOracleContract) GetMinBondLPP(ctx context.Context) (*big.Int, e
return period, nil
}
func (c *PreimageOracleContract) decodePreimageIdent(result *batching.CallResult) keccakTypes.LargePreimageIdent {
func (c *PreimageOracleContractLatest) decodePreimageIdent(result *batching.CallResult) keccakTypes.LargePreimageIdent {
return keccakTypes.LargePreimageIdent{
Claimant: result.GetAddress(0),
UUID: result.GetBigInt(1),
......@@ -428,3 +444,39 @@ func (m *metadata) setCountered(value bool) {
func (m *metadata) countered() bool {
return binary.BigEndian.Uint64(m[24:32]) != 0
}
type PreimageOracleContract interface {
Addr() common.Address
AddGlobalDataTx(data *types.PreimageOracleData) (txmgr.TxCandidate, error)
InitLargePreimage(uuid *big.Int, partOffset uint32, claimedSize uint32) (txmgr.TxCandidate, error)
AddLeaves(uuid *big.Int, startingBlockIndex *big.Int, input []byte, commitments []common.Hash, finalize bool) (txmgr.TxCandidate, error)
MinLargePreimageSize(ctx context.Context) (uint64, error)
ChallengePeriod(ctx context.Context) (uint64, error)
CallSqueeze(
ctx context.Context,
claimant common.Address,
uuid *big.Int,
prestateMatrix keccakTypes.StateSnapshot,
preState keccakTypes.Leaf,
preStateProof merkle.Proof,
postState keccakTypes.Leaf,
postStateProof merkle.Proof,
) error
Squeeze(
claimant common.Address,
uuid *big.Int,
prestateMatrix keccakTypes.StateSnapshot,
preState keccakTypes.Leaf,
preStateProof merkle.Proof,
postState keccakTypes.Leaf,
postStateProof merkle.Proof,
) (txmgr.TxCandidate, error)
GetActivePreimages(ctx context.Context, blockHash common.Hash) ([]keccakTypes.LargePreimageMetaData, error)
GetProposalMetadata(ctx context.Context, block rpcblock.Block, idents ...keccakTypes.LargePreimageIdent) ([]keccakTypes.LargePreimageMetaData, error)
GetProposalTreeRoot(ctx context.Context, block rpcblock.Block, ident keccakTypes.LargePreimageIdent) (common.Hash, error)
GetInputDataBlocks(ctx context.Context, block rpcblock.Block, ident keccakTypes.LargePreimageIdent) ([]uint64, error)
DecodeInputData(data []byte) (*big.Int, keccakTypes.InputData, error)
GlobalDataExists(ctx context.Context, data *types.PreimageOracleData) (bool, error)
ChallengeTx(ident keccakTypes.LargePreimageIdent, challenge keccakTypes.Challenge) (txmgr.TxCandidate, error)
GetMinBondLPP(ctx context.Context) (*big.Int, error)
}
package contracts
import (
_ "embed"
"math/big"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
preimage "github.com/ethereum-optimism/optimism/op-preimage"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common"
)
//go:embed abis/PreimageOracle-1.0.0.json
var preimageOracleAbi100 []byte
type PreimageOracleContract100 struct {
PreimageOracleContractLatest
}
func (c *PreimageOracleContract100) AddGlobalDataTx(data *types.PreimageOracleData) (txmgr.TxCandidate, error) {
if len(data.OracleKey) == 0 || preimage.KeyType(data.OracleKey[0]) != preimage.PrecompileKeyType {
return c.PreimageOracleContractLatest.AddGlobalDataTx(data)
}
inputs := data.GetPreimageWithoutSize()
call := c.contract.Call(methodLoadPrecompilePreimagePart,
new(big.Int).SetUint64(uint64(data.OracleOffset)),
common.BytesToAddress(inputs[0:20]),
inputs[20:])
return call.ToTxCandidate()
}
......@@ -17,272 +17,367 @@ import (
batchingTest "github.com/ethereum-optimism/optimism/op-service/sources/batching/test"
"github.com/ethereum-optimism/optimism/op-service/testutils"
"github.com/ethereum-optimism/optimism/packages/contracts-bedrock/snapshots"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
const (
oracle100 = "1.0.0"
oracleLatest = "1.1.0"
)
var oracleVersions = []contractVersion{
{
version: oracle100,
loadAbi: func() *abi.ABI {
return mustParseAbi(preimageOracleAbi100)
},
},
{
version: oracleLatest,
loadAbi: snapshots.LoadPreimageOracleABI,
},
}
func TestPreimageOracleContract_AddGlobalDataTx(t *testing.T) {
t.Run("UnknownType", func(t *testing.T) {
_, oracle := setupPreimageOracleTest(t)
data := types.NewPreimageOracleData(common.Hash{0xcc}.Bytes(), make([]byte, 20), uint32(545))
_, err := oracle.AddGlobalDataTx(data)
require.ErrorIs(t, err, ErrUnsupportedKeyType)
})
t.Run("Keccak256", func(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t)
data := types.NewPreimageOracleData(common.Hash{byte(preimage.Keccak256KeyType), 0xcc}.Bytes(), make([]byte, 20), uint32(545))
stubRpc.SetResponse(oracleAddr, methodLoadKeccak256PreimagePart, rpcblock.Latest, []interface{}{
new(big.Int).SetUint64(uint64(data.OracleOffset)),
data.GetPreimageWithoutSize(),
}, nil)
tx, err := oracle.AddGlobalDataTx(data)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
})
t.Run("Sha256", func(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t)
data := types.NewPreimageOracleData(common.Hash{byte(preimage.Sha256KeyType), 0xcc}.Bytes(), make([]byte, 20), uint32(545))
stubRpc.SetResponse(oracleAddr, methodLoadSha256PreimagePart, rpcblock.Latest, []interface{}{
new(big.Int).SetUint64(uint64(data.OracleOffset)),
data.GetPreimageWithoutSize(),
}, nil)
tx, err := oracle.AddGlobalDataTx(data)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
})
t.Run("Blob", func(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t)
fieldData := testutils.RandomData(rand.New(rand.NewSource(23)), 32)
data := types.NewPreimageOracleData(common.Hash{byte(preimage.BlobKeyType), 0xcc}.Bytes(), fieldData, uint32(545))
stubRpc.SetResponse(oracleAddr, methodLoadBlobPreimagePart, rpcblock.Latest, []interface{}{
new(big.Int).SetUint64(data.BlobFieldIndex),
new(big.Int).SetBytes(data.GetPreimageWithoutSize()),
data.BlobCommitment,
data.BlobProof,
new(big.Int).SetUint64(uint64(data.OracleOffset)),
}, nil)
tx, err := oracle.AddGlobalDataTx(data)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
})
t.Run("Precompile", func(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t)
input := testutils.RandomData(rand.New(rand.NewSource(23)), 200)
data := types.NewPreimageOracleData(common.Hash{byte(preimage.PrecompileKeyType), 0xcc}.Bytes(), input, uint32(545))
stubRpc.SetResponse(oracleAddr, methodLoadPrecompilePreimagePart, rpcblock.Latest, []interface{}{
new(big.Int).SetUint64(uint64(data.OracleOffset)),
data.GetPrecompileAddress(),
data.GetPrecompileInput(),
}, nil)
tx, err := oracle.AddGlobalDataTx(data)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
})
for _, version := range oracleVersions {
version := version
t.Run(version.version, func(t *testing.T) {
t.Run("UnknownType", func(t *testing.T) {
_, oracle := setupPreimageOracleTest(t, version)
data := types.NewPreimageOracleData(common.Hash{0xcc}.Bytes(), make([]byte, 20), uint32(545))
_, err := oracle.AddGlobalDataTx(data)
require.ErrorIs(t, err, ErrUnsupportedKeyType)
})
t.Run("Keccak256", func(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t, version)
data := types.NewPreimageOracleData(common.Hash{byte(preimage.Keccak256KeyType), 0xcc}.Bytes(), make([]byte, 20), uint32(545))
stubRpc.SetResponse(oracleAddr, methodLoadKeccak256PreimagePart, rpcblock.Latest, []interface{}{
new(big.Int).SetUint64(uint64(data.OracleOffset)),
data.GetPreimageWithoutSize(),
}, nil)
tx, err := oracle.AddGlobalDataTx(data)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
})
t.Run("Sha256", func(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t, version)
data := types.NewPreimageOracleData(common.Hash{byte(preimage.Sha256KeyType), 0xcc}.Bytes(), make([]byte, 20), uint32(545))
stubRpc.SetResponse(oracleAddr, methodLoadSha256PreimagePart, rpcblock.Latest, []interface{}{
new(big.Int).SetUint64(uint64(data.OracleOffset)),
data.GetPreimageWithoutSize(),
}, nil)
tx, err := oracle.AddGlobalDataTx(data)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
})
t.Run("Blob", func(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t, version)
fieldData := testutils.RandomData(rand.New(rand.NewSource(23)), 32)
data := types.NewPreimageOracleData(common.Hash{byte(preimage.BlobKeyType), 0xcc}.Bytes(), fieldData, uint32(545))
stubRpc.SetResponse(oracleAddr, methodLoadBlobPreimagePart, rpcblock.Latest, []interface{}{
new(big.Int).SetUint64(data.BlobFieldIndex),
new(big.Int).SetBytes(data.GetPreimageWithoutSize()),
data.BlobCommitment,
data.BlobProof,
new(big.Int).SetUint64(uint64(data.OracleOffset)),
}, nil)
tx, err := oracle.AddGlobalDataTx(data)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
})
t.Run("Precompile", func(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t, version)
input := testutils.RandomData(rand.New(rand.NewSource(23)), 200)
data := types.NewPreimageOracleData(common.Hash{byte(preimage.PrecompileKeyType), 0xcc}.Bytes(), input, uint32(545))
if version.Is(oracle100) {
keyData := data.GetPreimageWithoutSize()
stubRpc.SetResponse(oracleAddr, methodLoadPrecompilePreimagePart, rpcblock.Latest, []interface{}{
new(big.Int).SetUint64(uint64(data.OracleOffset)),
common.BytesToAddress(keyData[0:20]),
keyData[20:],
}, nil)
} else {
stubRpc.SetResponse(oracleAddr, methodLoadPrecompilePreimagePart, rpcblock.Latest, []interface{}{
new(big.Int).SetUint64(uint64(data.OracleOffset)),
data.GetPrecompileAddress(),
data.GetPrecompileRequiredGas(),
data.GetPrecompileInput(),
}, nil)
}
tx, err := oracle.AddGlobalDataTx(data)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
})
})
}
}
func TestPreimageOracleContract_ChallengePeriod(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t)
stubRpc.SetResponse(oracleAddr, methodChallengePeriod, rpcblock.Latest,
[]interface{}{},
[]interface{}{big.NewInt(123)},
)
challengePeriod, err := oracle.ChallengePeriod(context.Background())
require.NoError(t, err)
require.Equal(t, uint64(123), challengePeriod)
// Should cache responses
stubRpc.ClearResponses()
challengePeriod, err = oracle.ChallengePeriod(context.Background())
require.NoError(t, err)
require.Equal(t, uint64(123), challengePeriod)
for _, version := range oracleVersions {
version := version
t.Run(version.version, func(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t, version)
stubRpc.SetResponse(oracleAddr, methodChallengePeriod, rpcblock.Latest,
[]interface{}{},
[]interface{}{big.NewInt(123)},
)
challengePeriod, err := oracle.ChallengePeriod(context.Background())
require.NoError(t, err)
require.Equal(t, uint64(123), challengePeriod)
// Should cache responses
stubRpc.ClearResponses()
challengePeriod, err = oracle.ChallengePeriod(context.Background())
require.NoError(t, err)
require.Equal(t, uint64(123), challengePeriod)
})
}
}
func TestPreimageOracleContract_MinLargePreimageSize(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t)
stubRpc.SetResponse(oracleAddr, methodMinProposalSize, rpcblock.Latest,
[]interface{}{},
[]interface{}{big.NewInt(123)},
)
minProposalSize, err := oracle.MinLargePreimageSize(context.Background())
require.NoError(t, err)
require.Equal(t, uint64(123), minProposalSize)
for _, version := range oracleVersions {
version := version
t.Run(version.version, func(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t, version)
stubRpc.SetResponse(oracleAddr, methodMinProposalSize, rpcblock.Latest,
[]interface{}{},
[]interface{}{big.NewInt(123)},
)
minProposalSize, err := oracle.MinLargePreimageSize(context.Background())
require.NoError(t, err)
require.Equal(t, uint64(123), minProposalSize)
})
}
}
func TestPreimageOracleContract_MinBondSizeLPP(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t)
stubRpc.SetResponse(oracleAddr, methodMinBondSizeLPP, rpcblock.Latest,
[]interface{}{},
[]interface{}{big.NewInt(123)},
)
minBond, err := oracle.GetMinBondLPP(context.Background())
require.NoError(t, err)
require.Equal(t, big.NewInt(123), minBond)
// Should cache responses
stubRpc.ClearResponses()
minBond, err = oracle.GetMinBondLPP(context.Background())
require.NoError(t, err)
require.Equal(t, big.NewInt(123), minBond)
for _, version := range oracleVersions {
version := version
t.Run(version.version, func(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t, version)
stubRpc.SetResponse(oracleAddr, methodMinBondSizeLPP, rpcblock.Latest,
[]interface{}{},
[]interface{}{big.NewInt(123)},
)
minBond, err := oracle.GetMinBondLPP(context.Background())
require.NoError(t, err)
require.Equal(t, big.NewInt(123), minBond)
// Should cache responses
stubRpc.ClearResponses()
minBond, err = oracle.GetMinBondLPP(context.Background())
require.NoError(t, err)
require.Equal(t, big.NewInt(123), minBond)
})
}
}
func TestPreimageOracleContract_PreimageDataExists(t *testing.T) {
t.Run("exists", func(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t)
data := types.NewPreimageOracleData(common.Hash{0xcc}.Bytes(), make([]byte, 20), 545)
stubRpc.SetResponse(oracleAddr, methodPreimagePartOk, rpcblock.Latest,
[]interface{}{common.Hash(data.OracleKey), new(big.Int).SetUint64(uint64(data.OracleOffset))},
[]interface{}{true},
)
exists, err := oracle.GlobalDataExists(context.Background(), data)
require.NoError(t, err)
require.True(t, exists)
})
t.Run("does not exist", func(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t)
data := types.NewPreimageOracleData(common.Hash{0xcc}.Bytes(), make([]byte, 20), 545)
stubRpc.SetResponse(oracleAddr, methodPreimagePartOk, rpcblock.Latest,
[]interface{}{common.Hash(data.OracleKey), new(big.Int).SetUint64(uint64(data.OracleOffset))},
[]interface{}{false},
)
exists, err := oracle.GlobalDataExists(context.Background(), data)
require.NoError(t, err)
require.False(t, exists)
})
for _, version := range oracleVersions {
version := version
t.Run(version.version, func(t *testing.T) {
t.Run("exists", func(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t, version)
data := types.NewPreimageOracleData(common.Hash{0xcc}.Bytes(), make([]byte, 20), 545)
stubRpc.SetResponse(oracleAddr, methodPreimagePartOk, rpcblock.Latest,
[]interface{}{common.Hash(data.OracleKey), new(big.Int).SetUint64(uint64(data.OracleOffset))},
[]interface{}{true},
)
exists, err := oracle.GlobalDataExists(context.Background(), data)
require.NoError(t, err)
require.True(t, exists)
})
t.Run("does not exist", func(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t, version)
data := types.NewPreimageOracleData(common.Hash{0xcc}.Bytes(), make([]byte, 20), 545)
stubRpc.SetResponse(oracleAddr, methodPreimagePartOk, rpcblock.Latest,
[]interface{}{common.Hash(data.OracleKey), new(big.Int).SetUint64(uint64(data.OracleOffset))},
[]interface{}{false},
)
exists, err := oracle.GlobalDataExists(context.Background(), data)
require.NoError(t, err)
require.False(t, exists)
})
})
}
}
func TestPreimageOracleContract_InitLargePreimage(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t)
uuid := big.NewInt(123)
partOffset := uint32(1)
claimedSize := uint32(2)
bond := big.NewInt(42984)
stubRpc.SetResponse(oracleAddr, methodMinBondSizeLPP, rpcblock.Latest, nil, []interface{}{bond})
stubRpc.SetResponse(oracleAddr, methodInitLPP, rpcblock.Latest, []interface{}{
uuid,
partOffset,
claimedSize,
}, nil)
tx, err := oracle.InitLargePreimage(uuid, partOffset, claimedSize)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
require.Truef(t, bond.Cmp(tx.Value) == 0, "Expected bond %v got %v", bond, tx.Value)
for _, version := range oracleVersions {
version := version
t.Run(version.version, func(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t, version)
uuid := big.NewInt(123)
partOffset := uint32(1)
claimedSize := uint32(2)
bond := big.NewInt(42984)
stubRpc.SetResponse(oracleAddr, methodMinBondSizeLPP, rpcblock.Latest, nil, []interface{}{bond})
stubRpc.SetResponse(oracleAddr, methodInitLPP, rpcblock.Latest, []interface{}{
uuid,
partOffset,
claimedSize,
}, nil)
tx, err := oracle.InitLargePreimage(uuid, partOffset, claimedSize)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
require.Truef(t, bond.Cmp(tx.Value) == 0, "Expected bond %v got %v", bond, tx.Value)
})
}
}
func TestPreimageOracleContract_AddLeaves(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t)
uuid := big.NewInt(123)
startingBlockIndex := big.NewInt(0)
input := []byte{0x12}
commitments := []common.Hash{{0x34}}
finalize := true
stubRpc.SetResponse(oracleAddr, methodAddLeavesLPP, rpcblock.Latest, []interface{}{
uuid,
startingBlockIndex,
input,
commitments,
finalize,
}, nil)
tx, err := oracle.AddLeaves(uuid, startingBlockIndex, input, commitments, finalize)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
for _, version := range oracleVersions {
version := version
t.Run(version.version, func(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t, version)
uuid := big.NewInt(123)
startingBlockIndex := big.NewInt(0)
input := []byte{0x12}
commitments := []common.Hash{{0x34}}
finalize := true
stubRpc.SetResponse(oracleAddr, methodAddLeavesLPP, rpcblock.Latest, []interface{}{
uuid,
startingBlockIndex,
input,
commitments,
finalize,
}, nil)
tx, err := oracle.AddLeaves(uuid, startingBlockIndex, input, commitments, finalize)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
})
}
}
func TestPreimageOracleContract_Squeeze(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t)
claimant := common.Address{0x12}
uuid := big.NewInt(123)
preStateMatrix := keccakTypes.StateSnapshot{0, 1, 2, 3, 4}
preState := keccakTypes.Leaf{
Input: [keccakTypes.BlockSize]byte{0x12},
Index: 123,
StateCommitment: common.Hash{0x34},
}
preStateProof := merkle.Proof{{0x34}}
postState := keccakTypes.Leaf{
Input: [keccakTypes.BlockSize]byte{0x34},
Index: 456,
StateCommitment: common.Hash{0x56},
for _, version := range oracleVersions {
version := version
t.Run(version.version, func(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t, version)
claimant := common.Address{0x12}
uuid := big.NewInt(123)
preStateMatrix := keccakTypes.StateSnapshot{0, 1, 2, 3, 4}
preState := keccakTypes.Leaf{
Input: [keccakTypes.BlockSize]byte{0x12},
Index: 123,
StateCommitment: common.Hash{0x34},
}
preStateProof := merkle.Proof{{0x34}}
postState := keccakTypes.Leaf{
Input: [keccakTypes.BlockSize]byte{0x34},
Index: 456,
StateCommitment: common.Hash{0x56},
}
postStateProof := merkle.Proof{{0x56}}
stubRpc.SetResponse(oracleAddr, methodSqueezeLPP, rpcblock.Latest, []interface{}{
claimant,
uuid,
abiEncodeSnapshot(preStateMatrix),
toPreimageOracleLeaf(preState),
preStateProof,
toPreimageOracleLeaf(postState),
postStateProof,
}, nil)
tx, err := oracle.Squeeze(claimant, uuid, preStateMatrix, preState, preStateProof, postState, postStateProof)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
})
}
postStateProof := merkle.Proof{{0x56}}
stubRpc.SetResponse(oracleAddr, methodSqueezeLPP, rpcblock.Latest, []interface{}{
claimant,
uuid,
abiEncodeSnapshot(preStateMatrix),
toPreimageOracleLeaf(preState),
preStateProof,
toPreimageOracleLeaf(postState),
postStateProof,
}, nil)
tx, err := oracle.Squeeze(claimant, uuid, preStateMatrix, preState, preStateProof, postState, postStateProof)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
}
func TestGetActivePreimages(t *testing.T) {
blockHash := common.Hash{0xaa}
_, oracle, proposals := setupPreimageOracleTestWithProposals(t, rpcblock.ByHash(blockHash))
preimages, err := oracle.GetActivePreimages(context.Background(), blockHash)
require.NoError(t, err)
require.Equal(t, proposals, preimages)
for _, version := range oracleVersions {
version := version
t.Run(version.version, func(t *testing.T) {
blockHash := common.Hash{0xaa}
_, oracle, proposals := setupPreimageOracleTestWithProposals(t, version, rpcblock.ByHash(blockHash))
preimages, err := oracle.GetActivePreimages(context.Background(), blockHash)
require.NoError(t, err)
require.Equal(t, proposals, preimages)
})
}
}
func TestGetProposalMetadata(t *testing.T) {
blockHash := common.Hash{0xaa}
block := rpcblock.ByHash(blockHash)
stubRpc, oracle, proposals := setupPreimageOracleTestWithProposals(t, block)
preimages, err := oracle.GetProposalMetadata(
context.Background(),
block,
proposals[0].LargePreimageIdent,
proposals[1].LargePreimageIdent,
proposals[2].LargePreimageIdent,
)
require.NoError(t, err)
require.Equal(t, proposals, preimages)
// Fetching a proposal that doesn't exist should return an empty metadata object.
ident := keccakTypes.LargePreimageIdent{Claimant: common.Address{0x12}, UUID: big.NewInt(123)}
meta := new(metadata)
stubRpc.SetResponse(
oracleAddr,
methodProposalMetadata,
block,
[]interface{}{ident.Claimant, ident.UUID},
[]interface{}{meta})
preimages, err = oracle.GetProposalMetadata(context.Background(), rpcblock.ByHash(blockHash), ident)
require.NoError(t, err)
require.Equal(t, []keccakTypes.LargePreimageMetaData{{LargePreimageIdent: ident}}, preimages)
for _, version := range oracleVersions {
version := version
t.Run(version.version, func(t *testing.T) {
blockHash := common.Hash{0xaa}
block := rpcblock.ByHash(blockHash)
stubRpc, oracle, proposals := setupPreimageOracleTestWithProposals(t, version, block)
preimages, err := oracle.GetProposalMetadata(
context.Background(),
block,
proposals[0].LargePreimageIdent,
proposals[1].LargePreimageIdent,
proposals[2].LargePreimageIdent,
)
require.NoError(t, err)
require.Equal(t, proposals, preimages)
// Fetching a proposal that doesn't exist should return an empty metadata object.
ident := keccakTypes.LargePreimageIdent{Claimant: common.Address{0x12}, UUID: big.NewInt(123)}
meta := new(metadata)
stubRpc.SetResponse(
oracleAddr,
methodProposalMetadata,
block,
[]interface{}{ident.Claimant, ident.UUID},
[]interface{}{meta})
preimages, err = oracle.GetProposalMetadata(context.Background(), rpcblock.ByHash(blockHash), ident)
require.NoError(t, err)
require.Equal(t, []keccakTypes.LargePreimageMetaData{{LargePreimageIdent: ident}}, preimages)
})
}
}
func TestGetProposalTreeRoot(t *testing.T) {
blockHash := common.Hash{0xaa}
expectedRoot := common.Hash{0xbb}
ident := keccakTypes.LargePreimageIdent{Claimant: common.Address{0x12}, UUID: big.NewInt(123)}
stubRpc, oracle := setupPreimageOracleTest(t)
stubRpc.SetResponse(oracleAddr, methodGetTreeRootLPP, rpcblock.ByHash(blockHash),
[]interface{}{ident.Claimant, ident.UUID},
[]interface{}{expectedRoot})
actualRoot, err := oracle.GetProposalTreeRoot(context.Background(), rpcblock.ByHash(blockHash), ident)
require.NoError(t, err)
require.Equal(t, expectedRoot, actualRoot)
for _, version := range oracleVersions {
version := version
t.Run(version.version, func(t *testing.T) {
blockHash := common.Hash{0xaa}
expectedRoot := common.Hash{0xbb}
ident := keccakTypes.LargePreimageIdent{Claimant: common.Address{0x12}, UUID: big.NewInt(123)}
stubRpc, oracle := setupPreimageOracleTest(t, version)
stubRpc.SetResponse(oracleAddr, methodGetTreeRootLPP, rpcblock.ByHash(blockHash),
[]interface{}{ident.Claimant, ident.UUID},
[]interface{}{expectedRoot})
actualRoot, err := oracle.GetProposalTreeRoot(context.Background(), rpcblock.ByHash(blockHash), ident)
require.NoError(t, err)
require.Equal(t, expectedRoot, actualRoot)
})
}
}
func setupPreimageOracleTestWithProposals(t *testing.T, block rpcblock.Block) (*batchingTest.AbiBasedRpc, *PreimageOracleContract, []keccakTypes.LargePreimageMetaData) {
stubRpc, oracle := setupPreimageOracleTest(t)
func setupPreimageOracleTestWithProposals(t *testing.T, version contractVersion, block rpcblock.Block) (*batchingTest.AbiBasedRpc, PreimageOracleContract, []keccakTypes.LargePreimageMetaData) {
stubRpc, oracle := setupPreimageOracleTest(t, version)
stubRpc.SetResponse(
oracleAddr,
methodProposalCount,
......@@ -357,11 +452,11 @@ func setupPreimageOracleTestWithProposals(t *testing.T, block rpcblock.Block) (*
return stubRpc, oracle, proposals
}
func setupPreimageOracleTest(t *testing.T) (*batchingTest.AbiBasedRpc, *PreimageOracleContract) {
oracleAbi := snapshots.LoadPreimageOracleABI()
stubRpc := batchingTest.NewAbiBasedRpc(t, oracleAddr, oracleAbi)
oracleContract := NewPreimageOracleContract(oracleAddr, batching.NewMultiCaller(stubRpc, batching.DefaultBatchSize))
func setupPreimageOracleTest(t *testing.T, version contractVersion) (*batchingTest.AbiBasedRpc, PreimageOracleContract) {
stubRpc := batchingTest.NewAbiBasedRpc(t, oracleAddr, version.loadAbi())
stubRpc.SetResponse(oracleAddr, methodVersion, rpcblock.Latest, nil, []interface{}{version.version})
oracleContract, err := NewPreimageOracleContract(context.Background(), oracleAddr, batching.NewMultiCaller(stubRpc, batching.DefaultBatchSize))
require.NoError(t, err)
return stubRpc, oracleContract
}
......@@ -396,68 +491,93 @@ func TestMetadata(t *testing.T) {
}
for _, test := range tests {
test := test
for _, value := range uint32Values {
value := value
t.Run(fmt.Sprintf("%v-%v", test.name, value), func(t *testing.T) {
meta := new(metadata)
require.Zero(t, test.getter(meta))
test.setter(meta, value)
require.Equal(t, value, test.getter(meta))
for _, version := range oracleVersions {
version := version
t.Run(version.version, func(t *testing.T) {
for _, value := range uint32Values {
value := value
t.Run(fmt.Sprintf("%v-%v", test.name, value), func(t *testing.T) {
meta := new(metadata)
require.Zero(t, test.getter(meta))
test.setter(meta, value)
require.Equal(t, value, test.getter(meta))
})
}
})
}
}
}
func TestMetadata_Timestamp(t *testing.T) {
values := []uint64{0, 1, 2, 3252354, math.MaxUint32, math.MaxUint32 + 1, math.MaxUint64}
var meta metadata
require.Zero(t, meta.timestamp())
for _, value := range values {
meta.setTimestamp(value)
require.Equal(t, value, meta.timestamp())
for _, version := range oracleVersions {
version := version
t.Run(version.version, func(t *testing.T) {
values := []uint64{0, 1, 2, 3252354, math.MaxUint32, math.MaxUint32 + 1, math.MaxUint64}
var meta metadata
require.Zero(t, meta.timestamp())
for _, value := range values {
meta.setTimestamp(value)
require.Equal(t, value, meta.timestamp())
}
})
}
}
func TestMetadata_Countered(t *testing.T) {
var meta metadata
require.False(t, meta.countered())
meta.setCountered(true)
require.True(t, meta.countered())
meta.setCountered(false)
require.False(t, meta.countered())
for _, version := range oracleVersions {
version := version
t.Run(version.version, func(t *testing.T) {
var meta metadata
require.False(t, meta.countered())
meta.setCountered(true)
require.True(t, meta.countered())
meta.setCountered(false)
require.False(t, meta.countered())
})
}
}
func TestGetInputDataBlocks(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t)
block := rpcblock.ByHash(common.Hash{0xaa})
for _, version := range oracleVersions {
version := version
t.Run(version.version, func(t *testing.T) {
preimage := keccakTypes.LargePreimageIdent{
Claimant: common.Address{0xbb},
UUID: big.NewInt(2222),
}
stubRpc, oracle := setupPreimageOracleTest(t, version)
block := rpcblock.ByHash(common.Hash{0xaa})
stubRpc.SetResponse(
oracleAddr,
methodProposalBlocksLen,
block,
[]interface{}{preimage.Claimant, preimage.UUID},
[]interface{}{big.NewInt(3)})
preimage := keccakTypes.LargePreimageIdent{
Claimant: common.Address{0xbb},
UUID: big.NewInt(2222),
}
blockNums := []uint64{10, 35, 67}
stubRpc.SetResponse(
oracleAddr,
methodProposalBlocksLen,
block,
[]interface{}{preimage.Claimant, preimage.UUID},
[]interface{}{big.NewInt(3)})
blockNums := []uint64{10, 35, 67}
for i, blockNum := range blockNums {
stubRpc.SetResponse(
oracleAddr,
methodProposalBlocks,
block,
[]interface{}{preimage.Claimant, preimage.UUID, big.NewInt(int64(i))},
[]interface{}{blockNum})
}
for i, blockNum := range blockNums {
stubRpc.SetResponse(
oracleAddr,
methodProposalBlocks,
block,
[]interface{}{preimage.Claimant, preimage.UUID, big.NewInt(int64(i))},
[]interface{}{blockNum})
actual, err := oracle.GetInputDataBlocks(context.Background(), block, preimage)
require.NoError(t, err)
require.Len(t, actual, 3)
require.Equal(t, blockNums, actual)
})
}
actual, err := oracle.GetInputDataBlocks(context.Background(), block, preimage)
require.NoError(t, err)
require.Len(t, actual, 3)
require.Equal(t, blockNums, actual)
}
func TestDecodeInputData(t *testing.T) {
......@@ -472,7 +592,6 @@ func TestDecodeInputData(t *testing.T) {
Claimant: common.Address{0xaa},
UUID: big.NewInt(1111),
}
_, oracle := setupPreimageOracleTest(t)
tests := []struct {
name string
......@@ -553,106 +672,125 @@ func TestDecodeInputData(t *testing.T) {
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
var input []byte
if len(test.input) > 0 {
input = test.input
} else {
input = toAddLeavesTxData(t, oracle, ident.UUID, test.inputData)
}
require.Equal(t, test.expectedTxData, common.Bytes2Hex(input),
"ABI has been changed. Add tests to ensure historic transactions can be parsed before updating expectedTxData")
uuid, leaves, err := oracle.DecodeInputData(input)
if test.expectedErr != nil {
require.ErrorIs(t, err, test.expectedErr)
} else {
require.NoError(t, err)
require.Equal(t, ident.UUID, uuid)
require.Equal(t, test.inputData, leaves)
}
})
for _, version := range oracleVersions {
version := version
t.Run(version.version, func(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
_, oracle := setupPreimageOracleTest(t, version)
var input []byte
if len(test.input) > 0 {
input = test.input
} else {
input = toAddLeavesTxData(t, oracle, ident.UUID, test.inputData)
}
require.Equal(t, test.expectedTxData, common.Bytes2Hex(input),
"ABI has been changed. Add tests to ensure historic transactions can be parsed before updating expectedTxData")
uuid, leaves, err := oracle.DecodeInputData(input)
if test.expectedErr != nil {
require.ErrorIs(t, err, test.expectedErr)
} else {
require.NoError(t, err)
require.Equal(t, ident.UUID, uuid)
require.Equal(t, test.inputData, leaves)
}
})
})
}
}
}
func TestChallenge_First(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t)
for _, version := range oracleVersions {
version := version
t.Run(version.version, func(t *testing.T) {
ident := keccakTypes.LargePreimageIdent{
Claimant: common.Address{0xab},
UUID: big.NewInt(4829),
}
challenge := keccakTypes.Challenge{
StateMatrix: keccakTypes.StateSnapshot{1, 2, 3, 4, 5},
Prestate: keccakTypes.Leaf{},
Poststate: keccakTypes.Leaf{
Input: [136]byte{5, 4, 3, 2, 1},
Index: 0,
StateCommitment: common.Hash{0xbb},
},
PoststateProof: merkle.Proof{common.Hash{0x01}, common.Hash{0x02}},
stubRpc, oracle := setupPreimageOracleTest(t, version)
ident := keccakTypes.LargePreimageIdent{
Claimant: common.Address{0xab},
UUID: big.NewInt(4829),
}
challenge := keccakTypes.Challenge{
StateMatrix: keccakTypes.StateSnapshot{1, 2, 3, 4, 5},
Prestate: keccakTypes.Leaf{},
Poststate: keccakTypes.Leaf{
Input: [136]byte{5, 4, 3, 2, 1},
Index: 0,
StateCommitment: common.Hash{0xbb},
},
PoststateProof: merkle.Proof{common.Hash{0x01}, common.Hash{0x02}},
}
stubRpc.SetResponse(oracleAddr, methodChallengeFirstLPP, rpcblock.Latest,
[]interface{}{
ident.Claimant, ident.UUID,
preimageOracleLeaf{
Input: challenge.Poststate.Input[:],
Index: new(big.Int).SetUint64(challenge.Poststate.Index),
StateCommitment: challenge.Poststate.StateCommitment,
},
challenge.PoststateProof,
},
nil)
tx, err := oracle.ChallengeTx(ident, challenge)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
})
}
stubRpc.SetResponse(oracleAddr, methodChallengeFirstLPP, rpcblock.Latest,
[]interface{}{
ident.Claimant, ident.UUID,
preimageOracleLeaf{
Input: challenge.Poststate.Input[:],
Index: new(big.Int).SetUint64(challenge.Poststate.Index),
StateCommitment: challenge.Poststate.StateCommitment,
},
challenge.PoststateProof,
},
nil)
tx, err := oracle.ChallengeTx(ident, challenge)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
}
func TestChallenge_NotFirst(t *testing.T) {
stubRpc, oracle := setupPreimageOracleTest(t)
for _, version := range oracleVersions {
version := version
t.Run(version.version, func(t *testing.T) {
ident := keccakTypes.LargePreimageIdent{
Claimant: common.Address{0xab},
UUID: big.NewInt(4829),
}
challenge := keccakTypes.Challenge{
StateMatrix: keccakTypes.StateSnapshot{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
Prestate: keccakTypes.Leaf{
Input: [136]byte{9, 8, 7, 6, 5},
Index: 3,
StateCommitment: common.Hash{0xcc},
},
PrestateProof: merkle.Proof{common.Hash{0x01}, common.Hash{0x02}},
Poststate: keccakTypes.Leaf{
Input: [136]byte{5, 4, 3, 2, 1},
Index: 4,
StateCommitment: common.Hash{0xbb},
},
PoststateProof: merkle.Proof{common.Hash{0x03}, common.Hash{0x04}},
stubRpc, oracle := setupPreimageOracleTest(t, version)
ident := keccakTypes.LargePreimageIdent{
Claimant: common.Address{0xab},
UUID: big.NewInt(4829),
}
challenge := keccakTypes.Challenge{
StateMatrix: keccakTypes.StateSnapshot{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
Prestate: keccakTypes.Leaf{
Input: [136]byte{9, 8, 7, 6, 5},
Index: 3,
StateCommitment: common.Hash{0xcc},
},
PrestateProof: merkle.Proof{common.Hash{0x01}, common.Hash{0x02}},
Poststate: keccakTypes.Leaf{
Input: [136]byte{5, 4, 3, 2, 1},
Index: 4,
StateCommitment: common.Hash{0xbb},
},
PoststateProof: merkle.Proof{common.Hash{0x03}, common.Hash{0x04}},
}
stubRpc.SetResponse(oracleAddr, methodChallengeLPP, rpcblock.Latest,
[]interface{}{
ident.Claimant, ident.UUID,
libKeccakStateMatrix{State: challenge.StateMatrix},
preimageOracleLeaf{
Input: challenge.Prestate.Input[:],
Index: new(big.Int).SetUint64(challenge.Prestate.Index),
StateCommitment: challenge.Prestate.StateCommitment,
},
challenge.PrestateProof,
preimageOracleLeaf{
Input: challenge.Poststate.Input[:],
Index: new(big.Int).SetUint64(challenge.Poststate.Index),
StateCommitment: challenge.Poststate.StateCommitment,
},
challenge.PoststateProof,
},
nil)
tx, err := oracle.ChallengeTx(ident, challenge)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
})
}
stubRpc.SetResponse(oracleAddr, methodChallengeLPP, rpcblock.Latest,
[]interface{}{
ident.Claimant, ident.UUID,
libKeccakStateMatrix{State: challenge.StateMatrix},
preimageOracleLeaf{
Input: challenge.Prestate.Input[:],
Index: new(big.Int).SetUint64(challenge.Prestate.Index),
StateCommitment: challenge.Prestate.StateCommitment,
},
challenge.PrestateProof,
preimageOracleLeaf{
Input: challenge.Poststate.Input[:],
Index: new(big.Int).SetUint64(challenge.Poststate.Index),
StateCommitment: challenge.Poststate.StateCommitment,
},
challenge.PoststateProof,
},
nil)
tx, err := oracle.ChallengeTx(ident, challenge)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
}
func toAddLeavesTxData(t *testing.T, oracle *PreimageOracleContract, uuid *big.Int, inputData keccakTypes.InputData) []byte {
func toAddLeavesTxData(t *testing.T, oracle PreimageOracleContract, uuid *big.Int, inputData keccakTypes.InputData) []byte {
tx, err := oracle.AddLeaves(uuid, big.NewInt(1), inputData.Input, inputData.Commitments, inputData.Finalize)
require.NoError(t, err)
return tx.TxData
......
package contracts
import (
"context"
"fmt"
"strings"
"github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
)
var (
methodVersion = "version"
)
type version[C any] struct {
prefixes string
factory func() (C, error)
}
type VersionedBuilder[C any] struct {
versions []version[C]
}
func (v *VersionedBuilder[C]) AddVersion(major int, minor int, factory func() (C, error)) {
v.versions = append(v.versions, version[C]{fmt.Sprintf("%d.%d.", major, minor), factory})
}
func (v *VersionedBuilder[C]) Build(ctx context.Context, caller *batching.MultiCaller, contractAbi *abi.ABI, addr common.Address, defaultVersion func() (C, error)) (C, error) {
var nilC C
result, err := caller.SingleCall(ctx, rpcblock.Latest, batching.NewContractCall(contractAbi, addr, methodVersion))
if err != nil {
return nilC, fmt.Errorf("failed to retrieve version of dispute game %v: %w", addr, err)
}
contractVersion := result.GetString(0)
for _, version := range v.versions {
if strings.HasPrefix(contractVersion, version.prefixes) {
return version.factory()
}
}
return defaultVersion()
}
package contracts
import (
"context"
"testing"
"github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock"
batchingTest "github.com/ethereum-optimism/optimism/op-service/sources/batching/test"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
var versionABI = `[{
"inputs": [],
"name": "version",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
}]`
func TestVersionedBuilder(t *testing.T) {
var builder VersionedBuilder[string]
builder.AddVersion(1, 1, func() (string, error) { return "v1.1", nil })
builder.AddVersion(1, 2, func() (string, error) { return "v1.2", nil })
require.Equal(t, "v1.1", buildWithVersion(t, builder, "1.1.0"))
require.Equal(t, "v1.1", buildWithVersion(t, builder, "1.1.1"))
require.Equal(t, "v1.1", buildWithVersion(t, builder, "1.1.2"))
require.Equal(t, "default", buildWithVersion(t, builder, "1.10.0"))
}
func buildWithVersion(t *testing.T, builder VersionedBuilder[string], version string) string {
addr := common.Address{0xaa}
contractABI := mustParseAbi(([]byte)(versionABI))
stubRpc := batchingTest.NewAbiBasedRpc(t, addr, contractABI)
stubRpc.SetResponse(addr, methodVersion, rpcblock.Latest, nil, []interface{}{version})
actual, err := builder.Build(context.Background(), batching.NewMultiCaller(stubRpc, batching.DefaultBatchSize), contractABI, addr, func() (string, error) {
return "default", nil
})
require.NoError(t, err)
return actual
}
......@@ -33,10 +33,10 @@ func (c *VMContract) Addr() common.Address {
return c.contract.Addr()
}
func (c *VMContract) Oracle(ctx context.Context) (*PreimageOracleContract, error) {
func (c *VMContract) Oracle(ctx context.Context) (PreimageOracleContract, error) {
results, err := c.multiCaller.SingleCall(ctx, rpcblock.Latest, c.contract.Call(methodOracle))
if err != nil {
return nil, fmt.Errorf("failed to load oracle address: %w", err)
}
return NewPreimageOracleContract(results.GetAddress(0), c.multiCaller), nil
return NewPreimageOracleContract(ctx, results.GetAddress(0), c.multiCaller)
}
......@@ -21,6 +21,8 @@ func TestVMContract_Oracle(t *testing.T) {
vmContract := NewVMContract(vmAddr, batching.NewMultiCaller(stubRpc, batching.DefaultBatchSize))
stubRpc.SetResponse(vmAddr, methodOracle, rpcblock.Latest, nil, []interface{}{oracleAddr})
stubRpc.AddContract(oracleAddr, snapshots.LoadPreimageOracleABI())
stubRpc.SetResponse(oracleAddr, methodVersion, rpcblock.Latest, nil, []interface{}{oracleLatest})
oracleContract, err := vmContract.Oracle(context.Background())
require.NoError(t, err)
......
......@@ -60,7 +60,7 @@ type GameContract interface {
GetStatus(ctx context.Context) (gameTypes.GameStatus, error)
GetMaxGameDepth(ctx context.Context) (types.Depth, error)
GetMaxClockDuration(ctx context.Context) (time.Duration, error)
GetOracle(ctx context.Context) (*contracts.PreimageOracleContract, error)
GetOracle(ctx context.Context) (contracts.PreimageOracleContract, error)
GetL1Head(ctx context.Context) (common.Hash, error)
}
......
......@@ -2,6 +2,7 @@ package types
import (
"context"
"encoding/binary"
"errors"
"fmt"
"math"
......@@ -149,8 +150,12 @@ func (p *PreimageOracleData) GetPrecompileAddress() common.Address {
return common.BytesToAddress(p.oracleData[8:28])
}
func (p *PreimageOracleData) GetPrecompileRequiredGas() uint64 {
return binary.BigEndian.Uint64(p.oracleData[28:36])
}
func (p *PreimageOracleData) GetPrecompileInput() []byte {
return p.oracleData[28:]
return p.oracleData[36:]
}
// NewPreimageOracleData creates a new [PreimageOracleData] instance.
......
// 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
)
// LibKeccakStateMatrix is an auto generated low-level Go binding around an user-defined struct.
type LibKeccakStateMatrix struct {
State [25]uint64
}
// PreimageOracleLeaf is an auto generated low-level Go binding around an user-defined struct.
type PreimageOracleLeaf struct {
Input []byte
Index *big.Int
StateCommitment [32]byte
}
// PreimageOracleMetaData contains all meta data concerning the PreimageOracle contract.
var PreimageOracleMetaData = &bind.MetaData{
ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_minProposalSize\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_challengePeriod\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"KECCAK_TREE_DEPTH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_LEAF_COUNT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MIN_BOND_SIZE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"addLeavesLPP\",\"inputs\":[{\"name\":\"_uuid\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_inputStartBlock\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_input\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"_stateCommitments\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"},{\"name\":\"_finalize\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"challengeFirstLPP\",\"inputs\":[{\"name\":\"_claimant\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_uuid\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_postState\",\"type\":\"tuple\",\"internalType\":\"structPreimageOracle.Leaf\",\"components\":[{\"name\":\"input\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"index\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"stateCommitment\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"_postStateProof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"challengeLPP\",\"inputs\":[{\"name\":\"_claimant\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_uuid\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_stateMatrix\",\"type\":\"tuple\",\"internalType\":\"structLibKeccak.StateMatrix\",\"components\":[{\"name\":\"state\",\"type\":\"uint64[25]\",\"internalType\":\"uint64[25]\"}]},{\"name\":\"_preState\",\"type\":\"tuple\",\"internalType\":\"structPreimageOracle.Leaf\",\"components\":[{\"name\":\"input\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"index\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"stateCommitment\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"_preStateProof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"},{\"name\":\"_postState\",\"type\":\"tuple\",\"internalType\":\"structPreimageOracle.Leaf\",\"components\":[{\"name\":\"input\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"index\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"stateCommitment\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"_postStateProof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"challengePeriod\",\"inputs\":[],\"outputs\":[{\"name\":\"challengePeriod_\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getTreeRootLPP\",\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_uuid\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"treeRoot_\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initLPP\",\"inputs\":[{\"name\":\"_uuid\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_partOffset\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"_claimedSize\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"loadBlobPreimagePart\",\"inputs\":[{\"name\":\"_z\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_y\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_commitment\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"_proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"_partOffset\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"loadKeccak256PreimagePart\",\"inputs\":[{\"name\":\"_partOffset\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_preimage\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"loadLocalData\",\"inputs\":[{\"name\":\"_ident\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_localContext\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_word\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_size\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_partOffset\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"key_\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"loadPrecompilePreimagePart\",\"inputs\":[{\"name\":\"_partOffset\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_precompile\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_input\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"loadSha256PreimagePart\",\"inputs\":[{\"name\":\"_partOffset\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_preimage\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"minProposalSize\",\"inputs\":[],\"outputs\":[{\"name\":\"minProposalSize_\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"preimageLengths\",\"inputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"preimagePartOk\",\"inputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"preimageParts\",\"inputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proposalBlocks\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proposalBlocksLen\",\"inputs\":[{\"name\":\"_claimant\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_uuid\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"len_\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proposalBonds\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proposalBranches\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proposalCount\",\"inputs\":[],\"outputs\":[{\"name\":\"count_\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proposalMetadata\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"LPPMetaData\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proposalParts\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proposals\",\"inputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"claimant\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"uuid\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"readPreimage\",\"inputs\":[{\"name\":\"_key\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_offset\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"dat_\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"datLen_\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"squeezeLPP\",\"inputs\":[{\"name\":\"_claimant\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_uuid\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_stateMatrix\",\"type\":\"tuple\",\"internalType\":\"structLibKeccak.StateMatrix\",\"components\":[{\"name\":\"state\",\"type\":\"uint64[25]\",\"internalType\":\"uint64[25]\"}]},{\"name\":\"_preState\",\"type\":\"tuple\",\"internalType\":\"structPreimageOracle.Leaf\",\"components\":[{\"name\":\"input\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"index\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"stateCommitment\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"_preStateProof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"},{\"name\":\"_postState\",\"type\":\"tuple\",\"internalType\":\"structPreimageOracle.Leaf\",\"components\":[{\"name\":\"input\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"index\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"stateCommitment\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"_postStateProof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"version\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"zeroHashes\",\"inputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"error\",\"name\":\"ActiveProposal\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"AlreadyFinalized\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"BadProposal\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"BondTransferFailed\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InsufficientBond\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidInputSize\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidPreimage\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidProof\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotEOA\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotInitialized\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"PartOffsetOOB\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"PostStateMatches\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StatesNotContiguous\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"TreeSizeOverflow\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"WrongStartingBlock\",\"inputs\":[]}]",
Bin: "0x60c06040523480156200001157600080fd5b50604051620039f9380380620039f98339810160408190526200003491620000f3565b60a0829052608081905260005b6200004f600160106200012e565b811015620000ea57600381601081106200006d576200006d62000148565b01546003826010811062000085576200008562000148565b0154604080516020810193909352820152606001604051602081830303815290604052805190602001206003826001620000c091906200015e565b60108110620000d357620000d362000148565b015580620000e18162000179565b91505062000041565b50505062000195565b600080604083850312156200010757600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b60008282101562000143576200014362000118565b500390565b634e487b7160e01b600052603260045260246000fd5b6000821982111562000174576200017462000118565b500190565b6000600182016200018e576200018e62000118565b5060010190565b60805160a051613830620001c9600039600081816105ae0152611d5101526000818161068e01526115b901526138306000f3fe6080604052600436106101cd5760003560e01c80638dc4be11116100f7578063dd24f9bf11610095578063ec5efcbc11610064578063ec5efcbc1461065f578063f3f480d91461067f578063faf37bc7146106b2578063fef2b4ed146106c557600080fd5b8063dd24f9bf1461059f578063ddcd58de146105d2578063e03110e11461060a578063e15926111461063f57600080fd5b8063b2e67ba8116100d1578063b2e67ba814610512578063b4801e611461054a578063d18534b51461056a578063da35c6641461058a57600080fd5b80638dc4be11146104835780639d53a648146104a35780639d7e8769146104f257600080fd5b806354fd4d501161016f5780637917de1d1161013e5780637917de1d146103bf5780637ac54767146103df5780638542cf50146103ff578063882856ef1461044a57600080fd5b806354fd4d50146102dd57806361238bde146103335780636551927b1461036b5780637051472e146103a357600080fd5b80632055b36b116101ab5780632055b36b146102735780633909af5c146102885780634d52b4c9146102a857806352f0f3ad146102bd57600080fd5b8063013cf08b146101d25780630359a5631461022357806304697c7814610251575b600080fd5b3480156101de57600080fd5b506101f26101ed366004612d2f565b6106f2565b6040805173ffffffffffffffffffffffffffffffffffffffff90931683526020830191909152015b60405180910390f35b34801561022f57600080fd5b5061024361023e366004612d71565b610737565b60405190815260200161021a565b34801561025d57600080fd5b5061027161026c366004612de4565b61086f565b005b34801561027f57600080fd5b50610243601081565b34801561029457600080fd5b506102716102a3366004613008565b6109a5565b3480156102b457600080fd5b50610243610bfc565b3480156102c957600080fd5b506102436102d83660046130f4565b610c17565b3480156102e957600080fd5b506103266040518060400160405280600581526020017f302e322e3000000000000000000000000000000000000000000000000000000081525081565b60405161021a919061315b565b34801561033f57600080fd5b5061024361034e3660046131ac565b600160209081526000928352604080842090915290825290205481565b34801561037757600080fd5b50610243610386366004612d71565b601560209081526000928352604080842090915290825290205481565b3480156103af57600080fd5b506102436703782dace9d9000081565b3480156103cb57600080fd5b506102716103da3660046131ce565b610cec565b3480156103eb57600080fd5b506102436103fa366004612d2f565b6111ef565b34801561040b57600080fd5b5061043a61041a3660046131ac565b600260209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161021a565b34801561045657600080fd5b5061046a61046536600461326a565b611206565b60405167ffffffffffffffff909116815260200161021a565b34801561048f57600080fd5b5061027161049e36600461329d565b611260565b3480156104af57600080fd5b506102436104be366004612d71565b73ffffffffffffffffffffffffffffffffffffffff9091166000908152601860209081526040808320938352929052205490565b3480156104fe57600080fd5b5061027161050d3660046132e9565b61135b565b34801561051e57600080fd5b5061024361052d366004612d71565b601760209081526000928352604080842090915290825290205481565b34801561055657600080fd5b5061024361056536600461326a565b611512565b34801561057657600080fd5b50610271610585366004613008565b611544565b34801561059657600080fd5b50601354610243565b3480156105ab57600080fd5b507f0000000000000000000000000000000000000000000000000000000000000000610243565b3480156105de57600080fd5b506102436105ed366004612d71565b601660209081526000928352604080842090915290825290205481565b34801561061657600080fd5b5061062a6106253660046131ac565b611906565b6040805192835260208301919091520161021a565b34801561064b57600080fd5b5061027161065a36600461329d565b6119f7565b34801561066b57600080fd5b5061027161067a366004613375565b611aff565b34801561068b57600080fd5b507f0000000000000000000000000000000000000000000000000000000000000000610243565b6102716106c036600461340e565b611c85565b3480156106d157600080fd5b506102436106e0366004612d2f565b60006020819052908152604090205481565b6013818154811061070257600080fd5b60009182526020909120600290910201805460019091015473ffffffffffffffffffffffffffffffffffffffff909116915082565b73ffffffffffffffffffffffffffffffffffffffff82166000908152601560209081526040808320848452909152812054819061077a9060601c63ffffffff1690565b63ffffffff16905060005b6010811015610867578160011660010361080d5773ffffffffffffffffffffffffffffffffffffffff85166000908152601460209081526040808320878452909152902081601081106107da576107da61344a565b0154604080516020810192909252810184905260600160405160208183030381529060405280519060200120925061084e565b82600382601081106108215761082161344a565b01546040805160208101939093528201526060016040516020818303038152906040528051906020012092505b60019190911c908061085f816134a8565b915050610785565b505092915050565b600080600080608060146030823785878260140137601480870182207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f06000000000000000000000000000000000000000000000000000000000000001794506000908190889084018b5afa94503d60010191506008820189106108fc5763fe2549876000526004601cfd5b60c082901b81526008018481533d6000600183013e88017ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8015160008481526002602090815260408083208c8452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811790915587845282528083209b83529a81528a82209290925593845283905296909120959095555050505050565b60006109b18a8a610737565b90506109d486868360208b01356109cf6109ca8d6134e0565b611ef0565b611f30565b80156109f257506109f283838360208801356109cf6109ca8a6134e0565b610a28576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b866040013588604051602001610a3e91906135af565b6040516020818303038152906040528051906020012014610a8b576040517f1968a90200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b836020013587602001356001610aa191906135ed565b14610ad8576040517f9a3b119900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b2088610ae68680613605565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611f9192505050565b610b29886120ec565b836040013588604051602001610b3f91906135af565b6040516020818303038152906040528051906020012003610b8c576040517f9843145b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8a1660009081526015602090815260408083208c8452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000166001179055610bf08a8a33612894565b50505050505050505050565b6001610c0a6010600261378c565b610c149190613798565b81565b6000610c23868661294d565b9050610c308360086135ed565b821180610c3d5750602083115b15610c74576040517ffe25498700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000602081815260c085901b82526008959095528251828252600286526040808320858452875280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091558484528752808320948352938652838220558181529384905292205592915050565b60608115610d0557610cfe86866129fa565b9050610d3f565b85858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293505050505b3360009081526014602090815260408083208b845290915280822081516102008101928390529160109082845b815481526020019060010190808311610d6c57505050505090506000601560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008b81526020019081526020016000205490506000610ded8260601c63ffffffff1690565b63ffffffff169050333214610e2e576040517fba092d1600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e3e8260801c63ffffffff1690565b63ffffffff16600003610e7d576040517f87138d5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e878260c01c90565b67ffffffffffffffff1615610ec8576040517f475a253500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b898114610f01576040517f60f95d5a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f0e89898d8886612a73565b83516020850160888204881415608883061715610f33576307b1daf16000526004601cfd5b60405160c8810160405260005b83811015610fe3578083018051835260208101516020840152604081015160408401526060810151606084015260808101516080840152508460888301526088810460051b8b013560a883015260c882206001860195508560005b610200811015610fd8576001821615610fb85782818b0152610fd8565b8981015160009081526020938452604090209260019290921c9101610f9b565b505050608801610f40565b50505050600160106002610ff7919061378c565b6110019190613798565b81111561103a576040517f6229572300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110af61104d8360401c63ffffffff1690565b61105d9063ffffffff168a6135ed565b60401b7fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff606084901b167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff8516171790565b9150841561113c5777ffffffffffffffffffffffffffffffffffffffffffffffff82164260c01b1791506110e98260801c63ffffffff1690565b63ffffffff166110ff8360401c63ffffffff1690565b63ffffffff161461113c576040517f7b1dafd100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526014602090815260408083208e8452909152902061116290846010612ca5565b503360008181526018602090815260408083208f8452825280832080546001810182559084528284206004820401805460039092166008026101000a67ffffffffffffffff818102199093164390931602919091179055838352601582528083208f8452909152812084905560609190911b81523690601437366014016000a05050505050505050505050565b600381601081106111ff57600080fd5b0154905081565b6018602052826000526040600020602052816000526040600020818154811061122e57600080fd5b906000526020600020906004918282040191900660080292509250509054906101000a900467ffffffffffffffff1681565b60443560008060088301861061127e5763fe2549876000526004601cfd5b60c083901b60805260888386823786600882030151915060206000858360025afa9050806112ab57600080fd5b50600080517effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0400000000000000000000000000000000000000000000000000000000000000178082526002602090815260408084208a8552825280842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091558385528252808420998452988152888320939093558152908190529490942055505050565b600080603087600037602060006030600060025afa806113835763f91129696000526004601cfd5b6000517effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f010000000000000000000000000000000000000000000000000000000000000017608081815260a08c905260c08b905260308a60e037603088609083013760008060c083600a5afa925082611405576309bde3396000526004601cfd5b6028861061141b5763fe2549876000526004601cfd5b6000602882015278200000000000000000000000000000000000000000000000008152600881018b905285810151935060308a8237603081019b909b52505060509098207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0500000000000000000000000000000000000000000000000000000000000000176000818152600260209081526040808320868452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811790915584845282528083209583529481528482209a909a559081528089529190912096909655505050505050565b6014602052826000526040600020602052816000526040600020816010811061153a57600080fd5b0154925083915050565b73ffffffffffffffffffffffffffffffffffffffff891660009081526015602090815260408083208b845290915290205467ffffffffffffffff8116156115b7576040517fc334f06900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006115e28260c01c90565b6115f69067ffffffffffffffff1642613798565b1161162d576040517f55d4cbf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006116398b8b610737565b905061165287878360208c01356109cf6109ca8e6134e0565b8015611670575061167084848360208901356109cf6109ca8b6134e0565b6116a6576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8760400135896040516020016116bc91906135af565b6040516020818303038152906040528051906020012014611709576040517f1968a90200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84602001358860200135600161171f91906135ed565b141580611751575060016117398360601c63ffffffff1690565b61174391906137af565b63ffffffff16856020013514155b15611788576040517f9a3b119900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61179689610ae68780613605565b61179f896120ec565b60006117aa8a612bc6565b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f020000000000000000000000000000000000000000000000000000000000000017905060006118018460a01c63ffffffff1690565b67ffffffffffffffff169050600160026000848152602001908152602001600020600083815260200190815260200160002060006101000a81548160ff021916908315150217905550601760008e73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008d815260200190815260200160002054600160008481526020019081526020016000206000838152602001908152602001600020819055506118d38460801c63ffffffff1690565b600083815260208190526040902063ffffffff9190911690556118f78d8d81612894565b50505050505050505050505050565b6000828152600260209081526040808320848452909152812054819060ff1661198f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f7072652d696d616765206d757374206578697374000000000000000000000000604482015260640160405180910390fd5b50600083815260208181526040909120546119ab8160086135ed565b6119b68560206135ed565b106119d457836119c78260086135ed565b6119d19190613798565b91505b506000938452600160209081526040808620948652939052919092205492909150565b604435600080600883018610611a155763fe2549876000526004601cfd5b60c083901b6080526088838682378087017ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80151908490207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f02000000000000000000000000000000000000000000000000000000000000001760008181526002602090815260408083208b8452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811790915584845282528083209a83529981528982209390935590815290819052959095209190915550505050565b6000611b0b8686610737565b9050611b2483838360208801356109cf6109ca8a6134e0565b611b5a576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602084013515611b96576040517f9a3b119900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b9e612ce3565b611bac81610ae68780613605565b611bb5816120ec565b846040013581604051602001611bcb91906135af565b6040516020818303038152906040528051906020012003611c18576040517f9843145b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff87166000908152601560209081526040808320898452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000166001179055611c7c878733612894565b50505050505050565b6703782dace9d90000341015611cc7576040517fe92c469f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b333214611d00576040517fba092d1600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611d0b8160086137d4565b63ffffffff168263ffffffff1610611d4f576040517ffe25498700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000008163ffffffff161015611daf576040517f7b1dafd100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000818152601560209081526040808320878452825280832080547fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff1660a09790971b7fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff169690961760809590951b949094179094558251808401845282815280850186815260138054600181018255908452915160029092027f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0908101805473ffffffffffffffffffffffffffffffffffffffff9094167fffffffffffffffffffffffff000000000000000000000000000000000000000090941693909317909255517f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0919091015590815260168352818120938152929091529020349055565b6000816000015182602001518360400151604051602001611f13939291906137fc565b604051602081830303815290604052805190602001209050919050565b60008160005b6010811015611f84578060051b880135600186831c1660018114611f695760008481526020839052604090209350611f7a565b600082815260208590526040902093505b5050600101611f36565b5090931495945050505050565b6088815114611f9f57600080fd5b6020810160208301612020565b8260031b8201518060001a8160011a60081b178160021a60101b8260031a60181b17178160041a60201b8260051a60281b178260061a60301b8360071a60381b171717905061201a81612005868560059190911b015190565b1867ffffffffffffffff16600586901b840152565b50505050565b61202c60008383611fac565b61203860018383611fac565b61204460028383611fac565b61205060038383611fac565b61205c60048383611fac565b61206860058383611fac565b61207460068383611fac565b61208060078383611fac565b61208c60088383611fac565b61209860098383611fac565b6120a4600a8383611fac565b6120b0600b8383611fac565b6120bc600c8383611fac565b6120c8600d8383611fac565b6120d4600e8383611fac565b6120e0600f8383611fac565b61201a60108383611fac565b6040805178010000000000008082800000000000808a8000000080008000602082015279808b00000000800000018000000080008081800000000000800991810191909152788a00000000000000880000000080008009000000008000000a60608201527b8000808b800000000000008b8000000000008089800000000000800360808201527f80000000000080028000000000000080000000000000800a800000008000000a60a08201527f800000008000808180000000000080800000000080000001800000008000800860c082015260009060e00160405160208183030381529060405290506020820160208201612774565b6102808101516101e082015161014083015160a0840151845118189118186102a082015161020083015161016084015160c0850151602086015118189118186102c083015161022084015161018085015160e0860151604087015118189118186102e08401516102408501516101a0860151610100870151606088015118189118186103008501516102608601516101c0870151610120880151608089015118189118188084603f1c61229f8660011b67ffffffffffffffff1690565b18188584603f1c6122ba8660011b67ffffffffffffffff1690565b18188584603f1c6122d58660011b67ffffffffffffffff1690565b181895508483603f1c6122f28560011b67ffffffffffffffff1690565b181894508387603f1c61230f8960011b67ffffffffffffffff1690565b60208b01518b51861867ffffffffffffffff168c5291189190911897508118600181901b603f9190911c18935060c08801518118601481901c602c9190911b1867ffffffffffffffff1660208901526101208801518718602c81901c60149190911b1867ffffffffffffffff1660c08901526102c08801518618600381901c603d9190911b1867ffffffffffffffff166101208901526101c08801518718601981901c60279190911b1867ffffffffffffffff166102c08901526102808801518218602e81901c60129190911b1867ffffffffffffffff166101c089015260408801518618600281901c603e9190911b1867ffffffffffffffff166102808901526101808801518618601581901c602b9190911b1867ffffffffffffffff1660408901526101a08801518518602781901c60199190911b1867ffffffffffffffff166101808901526102608801518718603881901c60089190911b1867ffffffffffffffff166101a08901526102e08801518518600881901c60389190911b1867ffffffffffffffff166102608901526101e08801518218601781901c60299190911b1867ffffffffffffffff166102e089015260808801518718602581901c601b9190911b1867ffffffffffffffff166101e08901526103008801518718603281901c600e9190911b1867ffffffffffffffff1660808901526102a08801518118603e81901c60029190911b1867ffffffffffffffff166103008901526101008801518518600981901c60379190911b1867ffffffffffffffff166102a08901526102008801518118601381901c602d9190911b1867ffffffffffffffff1661010089015260a08801518218601c81901c60249190911b1867ffffffffffffffff1661020089015260608801518518602481901c601c9190911b1867ffffffffffffffff1660a08901526102408801518518602b81901c60159190911b1867ffffffffffffffff1660608901526102208801518618603181901c600f9190911b1867ffffffffffffffff166102408901526101608801518118603681901c600a9190911b1867ffffffffffffffff166102208901525060e08701518518603a81901c60069190911b1867ffffffffffffffff166101608801526101408701518118603d81901c60039190911b1867ffffffffffffffff1660e0880152505067ffffffffffffffff81166101408601525b5050505050565b600582811b8201805160018501831b8401805160028701851b8601805160038901871b8801805160048b0190981b8901805167ffffffffffffffff861985168918811690995283198a16861889169096528819861683188816909352841986168818871690528419831684189095169052919391929190611c7c565b61270e600082612687565b612719600582612687565b612724600a82612687565b61272f600f82612687565b61273a601482612687565b50565b612746816121e2565b61274f81612703565b600383901b820151815160c09190911c9061201a90821867ffffffffffffffff168352565b6127806000828461273d565b61278c6001828461273d565b6127986002828461273d565b6127a46003828461273d565b6127b06004828461273d565b6127bc6005828461273d565b6127c86006828461273d565b6127d46007828461273d565b6127e06008828461273d565b6127ec6009828461273d565b6127f8600a828461273d565b612804600b828461273d565b612810600c828461273d565b61281c600d828461273d565b612828600e828461273d565b612834600f828461273d565b6128406010828461273d565b61284c6011828461273d565b6128586012828461273d565b6128646013828461273d565b6128706014828461273d565b61287c6015828461273d565b6128886016828461273d565b61201a6017828461273d565b73ffffffffffffffffffffffffffffffffffffffff83811660009081526016602090815260408083208684529091528082208054908390559051909284169083908381818185875af1925050503d806000811461290d576040519150601f19603f3d011682016040523d82523d6000602084013e612912565b606091505b5050905080612680576040517f83e6cc6b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f01000000000000000000000000000000000000000000000000000000000000007effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316176129f3818360408051600093845233602052918152606090922091527effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01000000000000000000000000000000000000000000000000000000000000001790565b9392505050565b6060604051905081602082018181018286833760888306808015612a435760888290038501848101848103803687375060806001820353506001845160001a1784538652612a5a565b608836843760018353608060878401536088850186525b5050505050601f19603f82510116810160405292915050565b6000612a858260a01c63ffffffff1690565b67ffffffffffffffff1690506000612aa38360801c63ffffffff1690565b63ffffffff1690506000612abd8460401c63ffffffff1690565b63ffffffff169050600883108015612ad3575080155b15612b075760c082901b6000908152883560085283513382526017602090815260408084208a855290915290912055612bbc565b60088310158015612b25575080612b1f600885613798565b93508310155b8015612b395750612b3687826135ed565b83105b15612bbc576000612b4a8285613798565b905087612b588260206135ed565b10158015612b64575085155b15612b9b576040517ffe25498700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526017602090815260408083208a845290915290209089013590555b5050505050505050565b6000612c49565b66ff00ff00ff00ff8160081c1667ff00ff00ff00ff00612bf78360081b67ffffffffffffffff1690565b1617905065ffff0000ffff8160101c1667ffff0000ffff0000612c248360101b67ffffffffffffffff1690565b1617905060008160201c612c428360201b67ffffffffffffffff1690565b1792915050565b60808201516020830190612c6190612bcd565b612bcd565b6040820151612c6f90612bcd565b60401b17612c87612c5c60018460059190911b015190565b825160809190911b90612c9990612bcd565b60c01b17179392505050565b8260108101928215612cd3579160200282015b82811115612cd3578251825591602001919060010190612cb8565b50612cdf929150612cfb565b5090565b6040518060200160405280612cf6612d10565b905290565b5b80821115612cdf5760008155600101612cfc565b6040518061032001604052806019906020820280368337509192915050565b600060208284031215612d4157600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114612d6c57600080fd5b919050565b60008060408385031215612d8457600080fd5b612d8d83612d48565b946020939093013593505050565b60008083601f840112612dad57600080fd5b50813567ffffffffffffffff811115612dc557600080fd5b602083019150836020828501011115612ddd57600080fd5b9250929050565b60008060008060608587031215612dfa57600080fd5b84359350612e0a60208601612d48565b9250604085013567ffffffffffffffff811115612e2657600080fd5b612e3287828801612d9b565b95989497509550505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610320810167ffffffffffffffff81118282101715612e9157612e91612e3e565b60405290565b6040516060810167ffffffffffffffff81118282101715612e9157612e91612e3e565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715612f0157612f01612e3e565b604052919050565b6000610320808385031215612f1d57600080fd5b604051602080820167ffffffffffffffff8382108183111715612f4257612f42612e3e565b8160405283955087601f880112612f5857600080fd5b612f60612e6d565b9487019491508188861115612f7457600080fd5b875b86811015612f9c5780358381168114612f8f5760008081fd5b8452928401928401612f76565b50909352509295945050505050565b600060608284031215612fbd57600080fd5b50919050565b60008083601f840112612fd557600080fd5b50813567ffffffffffffffff811115612fed57600080fd5b6020830191508360208260051b8501011115612ddd57600080fd5b60008060008060008060008060006103e08a8c03121561302757600080fd5b6130308a612d48565b985060208a013597506130468b60408c01612f09565b96506103608a013567ffffffffffffffff8082111561306457600080fd5b6130708d838e01612fab565b97506103808c013591508082111561308757600080fd5b6130938d838e01612fc3565b90975095506103a08c01359150808211156130ad57600080fd5b6130b98d838e01612fab565b94506103c08c01359150808211156130d057600080fd5b506130dd8c828d01612fc3565b915080935050809150509295985092959850929598565b600080600080600060a0868803121561310c57600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b60005b8381101561314a578181015183820152602001613132565b8381111561201a5750506000910152565b602081526000825180602084015261317a81604085016020870161312f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b600080604083850312156131bf57600080fd5b50508035926020909101359150565b600080600080600080600060a0888a0312156131e957600080fd5b8735965060208801359550604088013567ffffffffffffffff8082111561320f57600080fd5b61321b8b838c01612d9b565b909750955060608a013591508082111561323457600080fd5b506132418a828b01612fc3565b9094509250506080880135801515811461325a57600080fd5b8091505092959891949750929550565b60008060006060848603121561327f57600080fd5b61328884612d48565b95602085013595506040909401359392505050565b6000806000604084860312156132b257600080fd5b83359250602084013567ffffffffffffffff8111156132d057600080fd5b6132dc86828701612d9b565b9497909650939450505050565b600080600080600080600060a0888a03121561330457600080fd5b8735965060208801359550604088013567ffffffffffffffff8082111561332a57600080fd5b6133368b838c01612d9b565b909750955060608a013591508082111561334f57600080fd5b5061335c8a828b01612d9b565b989b979a50959894979596608090950135949350505050565b60008060008060006080868803121561338d57600080fd5b61339686612d48565b945060208601359350604086013567ffffffffffffffff808211156133ba57600080fd5b6133c689838a01612fab565b945060608801359150808211156133dc57600080fd5b506133e988828901612fc3565b969995985093965092949392505050565b803563ffffffff81168114612d6c57600080fd5b60008060006060848603121561342357600080fd5b83359250613433602085016133fa565b9150613441604085016133fa565b90509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036134d9576134d9613479565b5060010190565b6000606082360312156134f257600080fd5b6134fa612e97565b823567ffffffffffffffff8082111561351257600080fd5b9084019036601f83011261352557600080fd5b813560208282111561353957613539612e3e565b613569817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85011601612eba565b9250818352368183860101111561357f57600080fd5b81818501828501376000918301810191909152908352848101359083015250604092830135928101929092525090565b81516103208201908260005b60198110156135e457825167ffffffffffffffff168252602092830192909101906001016135bb565b50505092915050565b6000821982111561360057613600613479565b500190565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261363a57600080fd5b83018035915067ffffffffffffffff82111561365557600080fd5b602001915036819003821315612ddd57600080fd5b600181815b808511156136c357817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156136a9576136a9613479565b808516156136b657918102915b93841c939080029061366f565b509250929050565b6000826136da57506001613786565b816136e757506000613786565b81600181146136fd576002811461370757613723565b6001915050613786565b60ff84111561371857613718613479565b50506001821b613786565b5060208310610133831016604e8410600b8410161715613746575081810a613786565b613750838361366a565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561378257613782613479565b0290505b92915050565b60006129f383836136cb565b6000828210156137aa576137aa613479565b500390565b600063ffffffff838116908316818110156137cc576137cc613479565b039392505050565b600063ffffffff8083168185168083038211156137f3576137f3613479565b01949350505050565b6000845161380e81846020890161312f565b9190910192835250602082015260400191905056fea164736f6c634300080f000a",
}
// 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, _minProposalSize *big.Int, _challengePeriod *big.Int) (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, _minProposalSize, _challengePeriod)
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...)
}
// KECCAKTREEDEPTH is a free data retrieval call binding the contract method 0x2055b36b.
//
// Solidity: function KECCAK_TREE_DEPTH() view returns(uint256)
func (_PreimageOracle *PreimageOracleCaller) KECCAKTREEDEPTH(opts *bind.CallOpts) (*big.Int, error) {
var out []interface{}
err := _PreimageOracle.contract.Call(opts, &out, "KECCAK_TREE_DEPTH")
if err != nil {
return *new(*big.Int), err
}
out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
return out0, err
}
// KECCAKTREEDEPTH is a free data retrieval call binding the contract method 0x2055b36b.
//
// Solidity: function KECCAK_TREE_DEPTH() view returns(uint256)
func (_PreimageOracle *PreimageOracleSession) KECCAKTREEDEPTH() (*big.Int, error) {
return _PreimageOracle.Contract.KECCAKTREEDEPTH(&_PreimageOracle.CallOpts)
}
// KECCAKTREEDEPTH is a free data retrieval call binding the contract method 0x2055b36b.
//
// Solidity: function KECCAK_TREE_DEPTH() view returns(uint256)
func (_PreimageOracle *PreimageOracleCallerSession) KECCAKTREEDEPTH() (*big.Int, error) {
return _PreimageOracle.Contract.KECCAKTREEDEPTH(&_PreimageOracle.CallOpts)
}
// MAXLEAFCOUNT is a free data retrieval call binding the contract method 0x4d52b4c9.
//
// Solidity: function MAX_LEAF_COUNT() view returns(uint256)
func (_PreimageOracle *PreimageOracleCaller) MAXLEAFCOUNT(opts *bind.CallOpts) (*big.Int, error) {
var out []interface{}
err := _PreimageOracle.contract.Call(opts, &out, "MAX_LEAF_COUNT")
if err != nil {
return *new(*big.Int), err
}
out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
return out0, err
}
// MAXLEAFCOUNT is a free data retrieval call binding the contract method 0x4d52b4c9.
//
// Solidity: function MAX_LEAF_COUNT() view returns(uint256)
func (_PreimageOracle *PreimageOracleSession) MAXLEAFCOUNT() (*big.Int, error) {
return _PreimageOracle.Contract.MAXLEAFCOUNT(&_PreimageOracle.CallOpts)
}
// MAXLEAFCOUNT is a free data retrieval call binding the contract method 0x4d52b4c9.
//
// Solidity: function MAX_LEAF_COUNT() view returns(uint256)
func (_PreimageOracle *PreimageOracleCallerSession) MAXLEAFCOUNT() (*big.Int, error) {
return _PreimageOracle.Contract.MAXLEAFCOUNT(&_PreimageOracle.CallOpts)
}
// MINBONDSIZE is a free data retrieval call binding the contract method 0x7051472e.
//
// Solidity: function MIN_BOND_SIZE() view returns(uint256)
func (_PreimageOracle *PreimageOracleCaller) MINBONDSIZE(opts *bind.CallOpts) (*big.Int, error) {
var out []interface{}
err := _PreimageOracle.contract.Call(opts, &out, "MIN_BOND_SIZE")
if err != nil {
return *new(*big.Int), err
}
out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
return out0, err
}
// MINBONDSIZE is a free data retrieval call binding the contract method 0x7051472e.
//
// Solidity: function MIN_BOND_SIZE() view returns(uint256)
func (_PreimageOracle *PreimageOracleSession) MINBONDSIZE() (*big.Int, error) {
return _PreimageOracle.Contract.MINBONDSIZE(&_PreimageOracle.CallOpts)
}
// MINBONDSIZE is a free data retrieval call binding the contract method 0x7051472e.
//
// Solidity: function MIN_BOND_SIZE() view returns(uint256)
func (_PreimageOracle *PreimageOracleCallerSession) MINBONDSIZE() (*big.Int, error) {
return _PreimageOracle.Contract.MINBONDSIZE(&_PreimageOracle.CallOpts)
}
// ChallengePeriod is a free data retrieval call binding the contract method 0xf3f480d9.
//
// Solidity: function challengePeriod() view returns(uint256 challengePeriod_)
func (_PreimageOracle *PreimageOracleCaller) ChallengePeriod(opts *bind.CallOpts) (*big.Int, error) {
var out []interface{}
err := _PreimageOracle.contract.Call(opts, &out, "challengePeriod")
if err != nil {
return *new(*big.Int), err
}
out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
return out0, err
}
// ChallengePeriod is a free data retrieval call binding the contract method 0xf3f480d9.
//
// Solidity: function challengePeriod() view returns(uint256 challengePeriod_)
func (_PreimageOracle *PreimageOracleSession) ChallengePeriod() (*big.Int, error) {
return _PreimageOracle.Contract.ChallengePeriod(&_PreimageOracle.CallOpts)
}
// ChallengePeriod is a free data retrieval call binding the contract method 0xf3f480d9.
//
// Solidity: function challengePeriod() view returns(uint256 challengePeriod_)
func (_PreimageOracle *PreimageOracleCallerSession) ChallengePeriod() (*big.Int, error) {
return _PreimageOracle.Contract.ChallengePeriod(&_PreimageOracle.CallOpts)
}
// GetTreeRootLPP is a free data retrieval call binding the contract method 0x0359a563.
//
// Solidity: function getTreeRootLPP(address _owner, uint256 _uuid) view returns(bytes32 treeRoot_)
func (_PreimageOracle *PreimageOracleCaller) GetTreeRootLPP(opts *bind.CallOpts, _owner common.Address, _uuid *big.Int) ([32]byte, error) {
var out []interface{}
err := _PreimageOracle.contract.Call(opts, &out, "getTreeRootLPP", _owner, _uuid)
if err != nil {
return *new([32]byte), err
}
out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte)
return out0, err
}
// GetTreeRootLPP is a free data retrieval call binding the contract method 0x0359a563.
//
// Solidity: function getTreeRootLPP(address _owner, uint256 _uuid) view returns(bytes32 treeRoot_)
func (_PreimageOracle *PreimageOracleSession) GetTreeRootLPP(_owner common.Address, _uuid *big.Int) ([32]byte, error) {
return _PreimageOracle.Contract.GetTreeRootLPP(&_PreimageOracle.CallOpts, _owner, _uuid)
}
// GetTreeRootLPP is a free data retrieval call binding the contract method 0x0359a563.
//
// Solidity: function getTreeRootLPP(address _owner, uint256 _uuid) view returns(bytes32 treeRoot_)
func (_PreimageOracle *PreimageOracleCallerSession) GetTreeRootLPP(_owner common.Address, _uuid *big.Int) ([32]byte, error) {
return _PreimageOracle.Contract.GetTreeRootLPP(&_PreimageOracle.CallOpts, _owner, _uuid)
}
// MinProposalSize is a free data retrieval call binding the contract method 0xdd24f9bf.
//
// Solidity: function minProposalSize() view returns(uint256 minProposalSize_)
func (_PreimageOracle *PreimageOracleCaller) MinProposalSize(opts *bind.CallOpts) (*big.Int, error) {
var out []interface{}
err := _PreimageOracle.contract.Call(opts, &out, "minProposalSize")
if err != nil {
return *new(*big.Int), err
}
out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
return out0, err
}
// MinProposalSize is a free data retrieval call binding the contract method 0xdd24f9bf.
//
// Solidity: function minProposalSize() view returns(uint256 minProposalSize_)
func (_PreimageOracle *PreimageOracleSession) MinProposalSize() (*big.Int, error) {
return _PreimageOracle.Contract.MinProposalSize(&_PreimageOracle.CallOpts)
}
// MinProposalSize is a free data retrieval call binding the contract method 0xdd24f9bf.
//
// Solidity: function minProposalSize() view returns(uint256 minProposalSize_)
func (_PreimageOracle *PreimageOracleCallerSession) MinProposalSize() (*big.Int, error) {
return _PreimageOracle.Contract.MinProposalSize(&_PreimageOracle.CallOpts)
}
// 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)
}
// ProposalBlocks is a free data retrieval call binding the contract method 0x882856ef.
//
// Solidity: function proposalBlocks(address , uint256 , uint256 ) view returns(uint64)
func (_PreimageOracle *PreimageOracleCaller) ProposalBlocks(opts *bind.CallOpts, arg0 common.Address, arg1 *big.Int, arg2 *big.Int) (uint64, error) {
var out []interface{}
err := _PreimageOracle.contract.Call(opts, &out, "proposalBlocks", arg0, arg1, arg2)
if err != nil {
return *new(uint64), err
}
out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
return out0, err
}
// ProposalBlocks is a free data retrieval call binding the contract method 0x882856ef.
//
// Solidity: function proposalBlocks(address , uint256 , uint256 ) view returns(uint64)
func (_PreimageOracle *PreimageOracleSession) ProposalBlocks(arg0 common.Address, arg1 *big.Int, arg2 *big.Int) (uint64, error) {
return _PreimageOracle.Contract.ProposalBlocks(&_PreimageOracle.CallOpts, arg0, arg1, arg2)
}
// ProposalBlocks is a free data retrieval call binding the contract method 0x882856ef.
//
// Solidity: function proposalBlocks(address , uint256 , uint256 ) view returns(uint64)
func (_PreimageOracle *PreimageOracleCallerSession) ProposalBlocks(arg0 common.Address, arg1 *big.Int, arg2 *big.Int) (uint64, error) {
return _PreimageOracle.Contract.ProposalBlocks(&_PreimageOracle.CallOpts, arg0, arg1, arg2)
}
// ProposalBlocksLen is a free data retrieval call binding the contract method 0x9d53a648.
//
// Solidity: function proposalBlocksLen(address _claimant, uint256 _uuid) view returns(uint256 len_)
func (_PreimageOracle *PreimageOracleCaller) ProposalBlocksLen(opts *bind.CallOpts, _claimant common.Address, _uuid *big.Int) (*big.Int, error) {
var out []interface{}
err := _PreimageOracle.contract.Call(opts, &out, "proposalBlocksLen", _claimant, _uuid)
if err != nil {
return *new(*big.Int), err
}
out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
return out0, err
}
// ProposalBlocksLen is a free data retrieval call binding the contract method 0x9d53a648.
//
// Solidity: function proposalBlocksLen(address _claimant, uint256 _uuid) view returns(uint256 len_)
func (_PreimageOracle *PreimageOracleSession) ProposalBlocksLen(_claimant common.Address, _uuid *big.Int) (*big.Int, error) {
return _PreimageOracle.Contract.ProposalBlocksLen(&_PreimageOracle.CallOpts, _claimant, _uuid)
}
// ProposalBlocksLen is a free data retrieval call binding the contract method 0x9d53a648.
//
// Solidity: function proposalBlocksLen(address _claimant, uint256 _uuid) view returns(uint256 len_)
func (_PreimageOracle *PreimageOracleCallerSession) ProposalBlocksLen(_claimant common.Address, _uuid *big.Int) (*big.Int, error) {
return _PreimageOracle.Contract.ProposalBlocksLen(&_PreimageOracle.CallOpts, _claimant, _uuid)
}
// ProposalBonds is a free data retrieval call binding the contract method 0xddcd58de.
//
// Solidity: function proposalBonds(address , uint256 ) view returns(uint256)
func (_PreimageOracle *PreimageOracleCaller) ProposalBonds(opts *bind.CallOpts, arg0 common.Address, arg1 *big.Int) (*big.Int, error) {
var out []interface{}
err := _PreimageOracle.contract.Call(opts, &out, "proposalBonds", arg0, arg1)
if err != nil {
return *new(*big.Int), err
}
out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
return out0, err
}
// ProposalBonds is a free data retrieval call binding the contract method 0xddcd58de.
//
// Solidity: function proposalBonds(address , uint256 ) view returns(uint256)
func (_PreimageOracle *PreimageOracleSession) ProposalBonds(arg0 common.Address, arg1 *big.Int) (*big.Int, error) {
return _PreimageOracle.Contract.ProposalBonds(&_PreimageOracle.CallOpts, arg0, arg1)
}
// ProposalBonds is a free data retrieval call binding the contract method 0xddcd58de.
//
// Solidity: function proposalBonds(address , uint256 ) view returns(uint256)
func (_PreimageOracle *PreimageOracleCallerSession) ProposalBonds(arg0 common.Address, arg1 *big.Int) (*big.Int, error) {
return _PreimageOracle.Contract.ProposalBonds(&_PreimageOracle.CallOpts, arg0, arg1)
}
// ProposalBranches is a free data retrieval call binding the contract method 0xb4801e61.
//
// Solidity: function proposalBranches(address , uint256 , uint256 ) view returns(bytes32)
func (_PreimageOracle *PreimageOracleCaller) ProposalBranches(opts *bind.CallOpts, arg0 common.Address, arg1 *big.Int, arg2 *big.Int) ([32]byte, error) {
var out []interface{}
err := _PreimageOracle.contract.Call(opts, &out, "proposalBranches", arg0, arg1, arg2)
if err != nil {
return *new([32]byte), err
}
out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte)
return out0, err
}
// ProposalBranches is a free data retrieval call binding the contract method 0xb4801e61.
//
// Solidity: function proposalBranches(address , uint256 , uint256 ) view returns(bytes32)
func (_PreimageOracle *PreimageOracleSession) ProposalBranches(arg0 common.Address, arg1 *big.Int, arg2 *big.Int) ([32]byte, error) {
return _PreimageOracle.Contract.ProposalBranches(&_PreimageOracle.CallOpts, arg0, arg1, arg2)
}
// ProposalBranches is a free data retrieval call binding the contract method 0xb4801e61.
//
// Solidity: function proposalBranches(address , uint256 , uint256 ) view returns(bytes32)
func (_PreimageOracle *PreimageOracleCallerSession) ProposalBranches(arg0 common.Address, arg1 *big.Int, arg2 *big.Int) ([32]byte, error) {
return _PreimageOracle.Contract.ProposalBranches(&_PreimageOracle.CallOpts, arg0, arg1, arg2)
}
// ProposalCount is a free data retrieval call binding the contract method 0xda35c664.
//
// Solidity: function proposalCount() view returns(uint256 count_)
func (_PreimageOracle *PreimageOracleCaller) ProposalCount(opts *bind.CallOpts) (*big.Int, error) {
var out []interface{}
err := _PreimageOracle.contract.Call(opts, &out, "proposalCount")
if err != nil {
return *new(*big.Int), err
}
out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
return out0, err
}
// ProposalCount is a free data retrieval call binding the contract method 0xda35c664.
//
// Solidity: function proposalCount() view returns(uint256 count_)
func (_PreimageOracle *PreimageOracleSession) ProposalCount() (*big.Int, error) {
return _PreimageOracle.Contract.ProposalCount(&_PreimageOracle.CallOpts)
}
// ProposalCount is a free data retrieval call binding the contract method 0xda35c664.
//
// Solidity: function proposalCount() view returns(uint256 count_)
func (_PreimageOracle *PreimageOracleCallerSession) ProposalCount() (*big.Int, error) {
return _PreimageOracle.Contract.ProposalCount(&_PreimageOracle.CallOpts)
}
// ProposalMetadata is a free data retrieval call binding the contract method 0x6551927b.
//
// Solidity: function proposalMetadata(address , uint256 ) view returns(bytes32)
func (_PreimageOracle *PreimageOracleCaller) ProposalMetadata(opts *bind.CallOpts, arg0 common.Address, arg1 *big.Int) ([32]byte, error) {
var out []interface{}
err := _PreimageOracle.contract.Call(opts, &out, "proposalMetadata", arg0, arg1)
if err != nil {
return *new([32]byte), err
}
out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte)
return out0, err
}
// ProposalMetadata is a free data retrieval call binding the contract method 0x6551927b.
//
// Solidity: function proposalMetadata(address , uint256 ) view returns(bytes32)
func (_PreimageOracle *PreimageOracleSession) ProposalMetadata(arg0 common.Address, arg1 *big.Int) ([32]byte, error) {
return _PreimageOracle.Contract.ProposalMetadata(&_PreimageOracle.CallOpts, arg0, arg1)
}
// ProposalMetadata is a free data retrieval call binding the contract method 0x6551927b.
//
// Solidity: function proposalMetadata(address , uint256 ) view returns(bytes32)
func (_PreimageOracle *PreimageOracleCallerSession) ProposalMetadata(arg0 common.Address, arg1 *big.Int) ([32]byte, error) {
return _PreimageOracle.Contract.ProposalMetadata(&_PreimageOracle.CallOpts, arg0, arg1)
}
// ProposalParts is a free data retrieval call binding the contract method 0xb2e67ba8.
//
// Solidity: function proposalParts(address , uint256 ) view returns(bytes32)
func (_PreimageOracle *PreimageOracleCaller) ProposalParts(opts *bind.CallOpts, arg0 common.Address, arg1 *big.Int) ([32]byte, error) {
var out []interface{}
err := _PreimageOracle.contract.Call(opts, &out, "proposalParts", arg0, arg1)
if err != nil {
return *new([32]byte), err
}
out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte)
return out0, err
}
// ProposalParts is a free data retrieval call binding the contract method 0xb2e67ba8.
//
// Solidity: function proposalParts(address , uint256 ) view returns(bytes32)
func (_PreimageOracle *PreimageOracleSession) ProposalParts(arg0 common.Address, arg1 *big.Int) ([32]byte, error) {
return _PreimageOracle.Contract.ProposalParts(&_PreimageOracle.CallOpts, arg0, arg1)
}
// ProposalParts is a free data retrieval call binding the contract method 0xb2e67ba8.
//
// Solidity: function proposalParts(address , uint256 ) view returns(bytes32)
func (_PreimageOracle *PreimageOracleCallerSession) ProposalParts(arg0 common.Address, arg1 *big.Int) ([32]byte, error) {
return _PreimageOracle.Contract.ProposalParts(&_PreimageOracle.CallOpts, arg0, arg1)
}
// Proposals is a free data retrieval call binding the contract method 0x013cf08b.
//
// Solidity: function proposals(uint256 ) view returns(address claimant, uint256 uuid)
func (_PreimageOracle *PreimageOracleCaller) Proposals(opts *bind.CallOpts, arg0 *big.Int) (struct {
Claimant common.Address
Uuid *big.Int
}, error) {
var out []interface{}
err := _PreimageOracle.contract.Call(opts, &out, "proposals", arg0)
outstruct := new(struct {
Claimant common.Address
Uuid *big.Int
})
if err != nil {
return *outstruct, err
}
outstruct.Claimant = *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
outstruct.Uuid = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int)
return *outstruct, err
}
// Proposals is a free data retrieval call binding the contract method 0x013cf08b.
//
// Solidity: function proposals(uint256 ) view returns(address claimant, uint256 uuid)
func (_PreimageOracle *PreimageOracleSession) Proposals(arg0 *big.Int) (struct {
Claimant common.Address
Uuid *big.Int
}, error) {
return _PreimageOracle.Contract.Proposals(&_PreimageOracle.CallOpts, arg0)
}
// Proposals is a free data retrieval call binding the contract method 0x013cf08b.
//
// Solidity: function proposals(uint256 ) view returns(address claimant, uint256 uuid)
func (_PreimageOracle *PreimageOracleCallerSession) Proposals(arg0 *big.Int) (struct {
Claimant common.Address
Uuid *big.Int
}, error) {
return _PreimageOracle.Contract.Proposals(&_PreimageOracle.CallOpts, arg0)
}
// 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)
}
// Version is a free data retrieval call binding the contract method 0x54fd4d50.
//
// Solidity: function version() view returns(string)
func (_PreimageOracle *PreimageOracleCaller) Version(opts *bind.CallOpts) (string, error) {
var out []interface{}
err := _PreimageOracle.contract.Call(opts, &out, "version")
if err != nil {
return *new(string), err
}
out0 := *abi.ConvertType(out[0], new(string)).(*string)
return out0, err
}
// Version is a free data retrieval call binding the contract method 0x54fd4d50.
//
// Solidity: function version() view returns(string)
func (_PreimageOracle *PreimageOracleSession) Version() (string, error) {
return _PreimageOracle.Contract.Version(&_PreimageOracle.CallOpts)
}
// Version is a free data retrieval call binding the contract method 0x54fd4d50.
//
// Solidity: function version() view returns(string)
func (_PreimageOracle *PreimageOracleCallerSession) Version() (string, error) {
return _PreimageOracle.Contract.Version(&_PreimageOracle.CallOpts)
}
// ZeroHashes is a free data retrieval call binding the contract method 0x7ac54767.
//
// Solidity: function zeroHashes(uint256 ) view returns(bytes32)
func (_PreimageOracle *PreimageOracleCaller) ZeroHashes(opts *bind.CallOpts, arg0 *big.Int) ([32]byte, error) {
var out []interface{}
err := _PreimageOracle.contract.Call(opts, &out, "zeroHashes", arg0)
if err != nil {
return *new([32]byte), err
}
out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte)
return out0, err
}
// ZeroHashes is a free data retrieval call binding the contract method 0x7ac54767.
//
// Solidity: function zeroHashes(uint256 ) view returns(bytes32)
func (_PreimageOracle *PreimageOracleSession) ZeroHashes(arg0 *big.Int) ([32]byte, error) {
return _PreimageOracle.Contract.ZeroHashes(&_PreimageOracle.CallOpts, arg0)
}
// ZeroHashes is a free data retrieval call binding the contract method 0x7ac54767.
//
// Solidity: function zeroHashes(uint256 ) view returns(bytes32)
func (_PreimageOracle *PreimageOracleCallerSession) ZeroHashes(arg0 *big.Int) ([32]byte, error) {
return _PreimageOracle.Contract.ZeroHashes(&_PreimageOracle.CallOpts, arg0)
}
// AddLeavesLPP is a paid mutator transaction binding the contract method 0x7917de1d.
//
// Solidity: function addLeavesLPP(uint256 _uuid, uint256 _inputStartBlock, bytes _input, bytes32[] _stateCommitments, bool _finalize) returns()
func (_PreimageOracle *PreimageOracleTransactor) AddLeavesLPP(opts *bind.TransactOpts, _uuid *big.Int, _inputStartBlock *big.Int, _input []byte, _stateCommitments [][32]byte, _finalize bool) (*types.Transaction, error) {
return _PreimageOracle.contract.Transact(opts, "addLeavesLPP", _uuid, _inputStartBlock, _input, _stateCommitments, _finalize)
}
// AddLeavesLPP is a paid mutator transaction binding the contract method 0x7917de1d.
//
// Solidity: function addLeavesLPP(uint256 _uuid, uint256 _inputStartBlock, bytes _input, bytes32[] _stateCommitments, bool _finalize) returns()
func (_PreimageOracle *PreimageOracleSession) AddLeavesLPP(_uuid *big.Int, _inputStartBlock *big.Int, _input []byte, _stateCommitments [][32]byte, _finalize bool) (*types.Transaction, error) {
return _PreimageOracle.Contract.AddLeavesLPP(&_PreimageOracle.TransactOpts, _uuid, _inputStartBlock, _input, _stateCommitments, _finalize)
}
// AddLeavesLPP is a paid mutator transaction binding the contract method 0x7917de1d.
//
// Solidity: function addLeavesLPP(uint256 _uuid, uint256 _inputStartBlock, bytes _input, bytes32[] _stateCommitments, bool _finalize) returns()
func (_PreimageOracle *PreimageOracleTransactorSession) AddLeavesLPP(_uuid *big.Int, _inputStartBlock *big.Int, _input []byte, _stateCommitments [][32]byte, _finalize bool) (*types.Transaction, error) {
return _PreimageOracle.Contract.AddLeavesLPP(&_PreimageOracle.TransactOpts, _uuid, _inputStartBlock, _input, _stateCommitments, _finalize)
}
// ChallengeFirstLPP is a paid mutator transaction binding the contract method 0xec5efcbc.
//
// Solidity: function challengeFirstLPP(address _claimant, uint256 _uuid, (bytes,uint256,bytes32) _postState, bytes32[] _postStateProof) returns()
func (_PreimageOracle *PreimageOracleTransactor) ChallengeFirstLPP(opts *bind.TransactOpts, _claimant common.Address, _uuid *big.Int, _postState PreimageOracleLeaf, _postStateProof [][32]byte) (*types.Transaction, error) {
return _PreimageOracle.contract.Transact(opts, "challengeFirstLPP", _claimant, _uuid, _postState, _postStateProof)
}
// ChallengeFirstLPP is a paid mutator transaction binding the contract method 0xec5efcbc.
//
// Solidity: function challengeFirstLPP(address _claimant, uint256 _uuid, (bytes,uint256,bytes32) _postState, bytes32[] _postStateProof) returns()
func (_PreimageOracle *PreimageOracleSession) ChallengeFirstLPP(_claimant common.Address, _uuid *big.Int, _postState PreimageOracleLeaf, _postStateProof [][32]byte) (*types.Transaction, error) {
return _PreimageOracle.Contract.ChallengeFirstLPP(&_PreimageOracle.TransactOpts, _claimant, _uuid, _postState, _postStateProof)
}
// ChallengeFirstLPP is a paid mutator transaction binding the contract method 0xec5efcbc.
//
// Solidity: function challengeFirstLPP(address _claimant, uint256 _uuid, (bytes,uint256,bytes32) _postState, bytes32[] _postStateProof) returns()
func (_PreimageOracle *PreimageOracleTransactorSession) ChallengeFirstLPP(_claimant common.Address, _uuid *big.Int, _postState PreimageOracleLeaf, _postStateProof [][32]byte) (*types.Transaction, error) {
return _PreimageOracle.Contract.ChallengeFirstLPP(&_PreimageOracle.TransactOpts, _claimant, _uuid, _postState, _postStateProof)
}
// ChallengeLPP is a paid mutator transaction binding the contract method 0x3909af5c.
//
// Solidity: function challengeLPP(address _claimant, uint256 _uuid, (uint64[25]) _stateMatrix, (bytes,uint256,bytes32) _preState, bytes32[] _preStateProof, (bytes,uint256,bytes32) _postState, bytes32[] _postStateProof) returns()
func (_PreimageOracle *PreimageOracleTransactor) ChallengeLPP(opts *bind.TransactOpts, _claimant common.Address, _uuid *big.Int, _stateMatrix LibKeccakStateMatrix, _preState PreimageOracleLeaf, _preStateProof [][32]byte, _postState PreimageOracleLeaf, _postStateProof [][32]byte) (*types.Transaction, error) {
return _PreimageOracle.contract.Transact(opts, "challengeLPP", _claimant, _uuid, _stateMatrix, _preState, _preStateProof, _postState, _postStateProof)
}
// ChallengeLPP is a paid mutator transaction binding the contract method 0x3909af5c.
//
// Solidity: function challengeLPP(address _claimant, uint256 _uuid, (uint64[25]) _stateMatrix, (bytes,uint256,bytes32) _preState, bytes32[] _preStateProof, (bytes,uint256,bytes32) _postState, bytes32[] _postStateProof) returns()
func (_PreimageOracle *PreimageOracleSession) ChallengeLPP(_claimant common.Address, _uuid *big.Int, _stateMatrix LibKeccakStateMatrix, _preState PreimageOracleLeaf, _preStateProof [][32]byte, _postState PreimageOracleLeaf, _postStateProof [][32]byte) (*types.Transaction, error) {
return _PreimageOracle.Contract.ChallengeLPP(&_PreimageOracle.TransactOpts, _claimant, _uuid, _stateMatrix, _preState, _preStateProof, _postState, _postStateProof)
}
// ChallengeLPP is a paid mutator transaction binding the contract method 0x3909af5c.
//
// Solidity: function challengeLPP(address _claimant, uint256 _uuid, (uint64[25]) _stateMatrix, (bytes,uint256,bytes32) _preState, bytes32[] _preStateProof, (bytes,uint256,bytes32) _postState, bytes32[] _postStateProof) returns()
func (_PreimageOracle *PreimageOracleTransactorSession) ChallengeLPP(_claimant common.Address, _uuid *big.Int, _stateMatrix LibKeccakStateMatrix, _preState PreimageOracleLeaf, _preStateProof [][32]byte, _postState PreimageOracleLeaf, _postStateProof [][32]byte) (*types.Transaction, error) {
return _PreimageOracle.Contract.ChallengeLPP(&_PreimageOracle.TransactOpts, _claimant, _uuid, _stateMatrix, _preState, _preStateProof, _postState, _postStateProof)
}
// InitLPP is a paid mutator transaction binding the contract method 0xfaf37bc7.
//
// Solidity: function initLPP(uint256 _uuid, uint32 _partOffset, uint32 _claimedSize) payable returns()
func (_PreimageOracle *PreimageOracleTransactor) InitLPP(opts *bind.TransactOpts, _uuid *big.Int, _partOffset uint32, _claimedSize uint32) (*types.Transaction, error) {
return _PreimageOracle.contract.Transact(opts, "initLPP", _uuid, _partOffset, _claimedSize)
}
// InitLPP is a paid mutator transaction binding the contract method 0xfaf37bc7.
//
// Solidity: function initLPP(uint256 _uuid, uint32 _partOffset, uint32 _claimedSize) payable returns()
func (_PreimageOracle *PreimageOracleSession) InitLPP(_uuid *big.Int, _partOffset uint32, _claimedSize uint32) (*types.Transaction, error) {
return _PreimageOracle.Contract.InitLPP(&_PreimageOracle.TransactOpts, _uuid, _partOffset, _claimedSize)
}
// InitLPP is a paid mutator transaction binding the contract method 0xfaf37bc7.
//
// Solidity: function initLPP(uint256 _uuid, uint32 _partOffset, uint32 _claimedSize) payable returns()
func (_PreimageOracle *PreimageOracleTransactorSession) InitLPP(_uuid *big.Int, _partOffset uint32, _claimedSize uint32) (*types.Transaction, error) {
return _PreimageOracle.Contract.InitLPP(&_PreimageOracle.TransactOpts, _uuid, _partOffset, _claimedSize)
}
// LoadBlobPreimagePart is a paid mutator transaction binding the contract method 0x9d7e8769.
//
// Solidity: function loadBlobPreimagePart(uint256 _z, uint256 _y, bytes _commitment, bytes _proof, uint256 _partOffset) returns()
func (_PreimageOracle *PreimageOracleTransactor) LoadBlobPreimagePart(opts *bind.TransactOpts, _z *big.Int, _y *big.Int, _commitment []byte, _proof []byte, _partOffset *big.Int) (*types.Transaction, error) {
return _PreimageOracle.contract.Transact(opts, "loadBlobPreimagePart", _z, _y, _commitment, _proof, _partOffset)
}
// LoadBlobPreimagePart is a paid mutator transaction binding the contract method 0x9d7e8769.
//
// Solidity: function loadBlobPreimagePart(uint256 _z, uint256 _y, bytes _commitment, bytes _proof, uint256 _partOffset) returns()
func (_PreimageOracle *PreimageOracleSession) LoadBlobPreimagePart(_z *big.Int, _y *big.Int, _commitment []byte, _proof []byte, _partOffset *big.Int) (*types.Transaction, error) {
return _PreimageOracle.Contract.LoadBlobPreimagePart(&_PreimageOracle.TransactOpts, _z, _y, _commitment, _proof, _partOffset)
}
// LoadBlobPreimagePart is a paid mutator transaction binding the contract method 0x9d7e8769.
//
// Solidity: function loadBlobPreimagePart(uint256 _z, uint256 _y, bytes _commitment, bytes _proof, uint256 _partOffset) returns()
func (_PreimageOracle *PreimageOracleTransactorSession) LoadBlobPreimagePart(_z *big.Int, _y *big.Int, _commitment []byte, _proof []byte, _partOffset *big.Int) (*types.Transaction, error) {
return _PreimageOracle.Contract.LoadBlobPreimagePart(&_PreimageOracle.TransactOpts, _z, _y, _commitment, _proof, _partOffset)
}
// 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)
}
// LoadLocalData is a paid mutator transaction binding the contract method 0x52f0f3ad.
//
// Solidity: function loadLocalData(uint256 _ident, bytes32 _localContext, bytes32 _word, uint256 _size, uint256 _partOffset) returns(bytes32 key_)
func (_PreimageOracle *PreimageOracleTransactor) LoadLocalData(opts *bind.TransactOpts, _ident *big.Int, _localContext [32]byte, _word [32]byte, _size *big.Int, _partOffset *big.Int) (*types.Transaction, error) {
return _PreimageOracle.contract.Transact(opts, "loadLocalData", _ident, _localContext, _word, _size, _partOffset)
}
// LoadLocalData is a paid mutator transaction binding the contract method 0x52f0f3ad.
//
// Solidity: function loadLocalData(uint256 _ident, bytes32 _localContext, bytes32 _word, uint256 _size, uint256 _partOffset) returns(bytes32 key_)
func (_PreimageOracle *PreimageOracleSession) LoadLocalData(_ident *big.Int, _localContext [32]byte, _word [32]byte, _size *big.Int, _partOffset *big.Int) (*types.Transaction, error) {
return _PreimageOracle.Contract.LoadLocalData(&_PreimageOracle.TransactOpts, _ident, _localContext, _word, _size, _partOffset)
}
// LoadLocalData is a paid mutator transaction binding the contract method 0x52f0f3ad.
//
// Solidity: function loadLocalData(uint256 _ident, bytes32 _localContext, bytes32 _word, uint256 _size, uint256 _partOffset) returns(bytes32 key_)
func (_PreimageOracle *PreimageOracleTransactorSession) LoadLocalData(_ident *big.Int, _localContext [32]byte, _word [32]byte, _size *big.Int, _partOffset *big.Int) (*types.Transaction, error) {
return _PreimageOracle.Contract.LoadLocalData(&_PreimageOracle.TransactOpts, _ident, _localContext, _word, _size, _partOffset)
}
// LoadPrecompilePreimagePart is a paid mutator transaction binding the contract method 0x04697c78.
//
// Solidity: function loadPrecompilePreimagePart(uint256 _partOffset, address _precompile, bytes _input) returns()
func (_PreimageOracle *PreimageOracleTransactor) LoadPrecompilePreimagePart(opts *bind.TransactOpts, _partOffset *big.Int, _precompile common.Address, _input []byte) (*types.Transaction, error) {
return _PreimageOracle.contract.Transact(opts, "loadPrecompilePreimagePart", _partOffset, _precompile, _input)
}
// LoadPrecompilePreimagePart is a paid mutator transaction binding the contract method 0x04697c78.
//
// Solidity: function loadPrecompilePreimagePart(uint256 _partOffset, address _precompile, bytes _input) returns()
func (_PreimageOracle *PreimageOracleSession) LoadPrecompilePreimagePart(_partOffset *big.Int, _precompile common.Address, _input []byte) (*types.Transaction, error) {
return _PreimageOracle.Contract.LoadPrecompilePreimagePart(&_PreimageOracle.TransactOpts, _partOffset, _precompile, _input)
}
// LoadPrecompilePreimagePart is a paid mutator transaction binding the contract method 0x04697c78.
//
// Solidity: function loadPrecompilePreimagePart(uint256 _partOffset, address _precompile, bytes _input) returns()
func (_PreimageOracle *PreimageOracleTransactorSession) LoadPrecompilePreimagePart(_partOffset *big.Int, _precompile common.Address, _input []byte) (*types.Transaction, error) {
return _PreimageOracle.Contract.LoadPrecompilePreimagePart(&_PreimageOracle.TransactOpts, _partOffset, _precompile, _input)
}
// LoadSha256PreimagePart is a paid mutator transaction binding the contract method 0x8dc4be11.
//
// Solidity: function loadSha256PreimagePart(uint256 _partOffset, bytes _preimage) returns()
func (_PreimageOracle *PreimageOracleTransactor) LoadSha256PreimagePart(opts *bind.TransactOpts, _partOffset *big.Int, _preimage []byte) (*types.Transaction, error) {
return _PreimageOracle.contract.Transact(opts, "loadSha256PreimagePart", _partOffset, _preimage)
}
// LoadSha256PreimagePart is a paid mutator transaction binding the contract method 0x8dc4be11.
//
// Solidity: function loadSha256PreimagePart(uint256 _partOffset, bytes _preimage) returns()
func (_PreimageOracle *PreimageOracleSession) LoadSha256PreimagePart(_partOffset *big.Int, _preimage []byte) (*types.Transaction, error) {
return _PreimageOracle.Contract.LoadSha256PreimagePart(&_PreimageOracle.TransactOpts, _partOffset, _preimage)
}
// LoadSha256PreimagePart is a paid mutator transaction binding the contract method 0x8dc4be11.
//
// Solidity: function loadSha256PreimagePart(uint256 _partOffset, bytes _preimage) returns()
func (_PreimageOracle *PreimageOracleTransactorSession) LoadSha256PreimagePart(_partOffset *big.Int, _preimage []byte) (*types.Transaction, error) {
return _PreimageOracle.Contract.LoadSha256PreimagePart(&_PreimageOracle.TransactOpts, _partOffset, _preimage)
}
// SqueezeLPP is a paid mutator transaction binding the contract method 0xd18534b5.
//
// Solidity: function squeezeLPP(address _claimant, uint256 _uuid, (uint64[25]) _stateMatrix, (bytes,uint256,bytes32) _preState, bytes32[] _preStateProof, (bytes,uint256,bytes32) _postState, bytes32[] _postStateProof) returns()
func (_PreimageOracle *PreimageOracleTransactor) SqueezeLPP(opts *bind.TransactOpts, _claimant common.Address, _uuid *big.Int, _stateMatrix LibKeccakStateMatrix, _preState PreimageOracleLeaf, _preStateProof [][32]byte, _postState PreimageOracleLeaf, _postStateProof [][32]byte) (*types.Transaction, error) {
return _PreimageOracle.contract.Transact(opts, "squeezeLPP", _claimant, _uuid, _stateMatrix, _preState, _preStateProof, _postState, _postStateProof)
}
// SqueezeLPP is a paid mutator transaction binding the contract method 0xd18534b5.
//
// Solidity: function squeezeLPP(address _claimant, uint256 _uuid, (uint64[25]) _stateMatrix, (bytes,uint256,bytes32) _preState, bytes32[] _preStateProof, (bytes,uint256,bytes32) _postState, bytes32[] _postStateProof) returns()
func (_PreimageOracle *PreimageOracleSession) SqueezeLPP(_claimant common.Address, _uuid *big.Int, _stateMatrix LibKeccakStateMatrix, _preState PreimageOracleLeaf, _preStateProof [][32]byte, _postState PreimageOracleLeaf, _postStateProof [][32]byte) (*types.Transaction, error) {
return _PreimageOracle.Contract.SqueezeLPP(&_PreimageOracle.TransactOpts, _claimant, _uuid, _stateMatrix, _preState, _preStateProof, _postState, _postStateProof)
}
// SqueezeLPP is a paid mutator transaction binding the contract method 0xd18534b5.
//
// Solidity: function squeezeLPP(address _claimant, uint256 _uuid, (uint64[25]) _stateMatrix, (bytes,uint256,bytes32) _preState, bytes32[] _preStateProof, (bytes,uint256,bytes32) _postState, bytes32[] _postStateProof) returns()
func (_PreimageOracle *PreimageOracleTransactorSession) SqueezeLPP(_claimant common.Address, _uuid *big.Int, _stateMatrix LibKeccakStateMatrix, _preState PreimageOracleLeaf, _preStateProof [][32]byte, _postState PreimageOracleLeaf, _postStateProof [][32]byte) (*types.Transaction, error) {
return _PreimageOracle.Contract.SqueezeLPP(&_PreimageOracle.TransactOpts, _claimant, _uuid, _stateMatrix, _preState, _preStateProof, _postState, _postStateProof)
}
......@@ -47,23 +47,49 @@ func (g *OutputCannonGameHelper) StartChallenger(ctx context.Context, name strin
return c
}
func (g *OutputCannonGameHelper) CreateHonestActor(ctx context.Context, l2Node string, options ...challenger.Option) *OutputHonestHelper {
opts := g.defaultChallengerOptions()
opts = append(opts, options...)
cfg := challenger.NewChallengerConfig(g.T, g.System, l2Node, opts...)
type honestActorConfig struct {
prestateBlock uint64
poststateBlock uint64
challengerOpts []challenger.Option
}
type HonestActorOpt func(cfg *honestActorConfig)
func WithClaimedL2BlockNumber(num uint64) HonestActorOpt {
return func(cfg *honestActorConfig) {
cfg.poststateBlock = num
}
}
func WithPrivKey(privKey *ecdsa.PrivateKey) HonestActorOpt {
return func(cfg *honestActorConfig) {
cfg.challengerOpts = append(cfg.challengerOpts, challenger.WithPrivKey(privKey))
}
}
func (g *OutputCannonGameHelper) CreateHonestActor(ctx context.Context, l2Node string, options ...HonestActorOpt) *OutputHonestHelper {
logger := testlog.Logger(g.T, log.LevelInfo).New("role", "HonestHelper", "game", g.Addr)
l2Client := g.System.NodeClient(l2Node)
prestateBlock, poststateBlock, err := g.Game.GetBlockRange(ctx)
realPrestateBlock, realPostStateBlock, err := g.Game.GetBlockRange(ctx)
g.Require.NoError(err, "Failed to load block range")
dir := filepath.Join(cfg.Datadir, "honest")
splitDepth := g.SplitDepth(ctx)
rollupClient := g.System.RollupClient(l2Node)
prestateProvider := outputs.NewPrestateProvider(rollupClient, prestateBlock)
actorCfg := &honestActorConfig{
prestateBlock: realPrestateBlock,
poststateBlock: realPostStateBlock,
challengerOpts: g.defaultChallengerOptions(),
}
for _, option := range options {
option(actorCfg)
}
cfg := challenger.NewChallengerConfig(g.T, g.System, l2Node, actorCfg.challengerOpts...)
dir := filepath.Join(cfg.Datadir, "honest")
prestateProvider := outputs.NewPrestateProvider(rollupClient, actorCfg.prestateBlock)
l1Head := g.GetL1Head(ctx)
accessor, err := outputs.NewOutputCannonTraceAccessor(
logger, metrics.NoopMetrics, cfg.Cannon, vm.NewOpProgramServerExecutor(), l2Client, prestateProvider, cfg.CannonAbsolutePreState, rollupClient, dir, l1Head, splitDepth, prestateBlock, poststateBlock)
logger, metrics.NoopMetrics, cfg.Cannon, vm.NewOpProgramServerExecutor(), l2Client, prestateProvider, cfg.CannonAbsolutePreState, rollupClient, dir, l1Head, splitDepth, actorCfg.prestateBlock, actorCfg.poststateBlock)
g.Require.NoError(err, "Failed to create output cannon trace accessor")
return NewOutputHonestHelper(g.T, g.Require, &g.OutputGameHelper, g.Game, accessor)
}
......@@ -128,7 +154,7 @@ func (g *OutputCannonGameHelper) ChallengeToPreimageLoad(ctx context.Context, ou
if preloadPreimage {
_, _, preimageData, err := provider.GetStepData(ctx, types.NewPosition(execDepth, big.NewInt(int64(targetTraceIndex))))
g.Require.NoError(err)
g.UploadPreimage(ctx, preimageData, challengerKey)
g.UploadPreimage(ctx, preimageData)
g.WaitForPreimageInOracle(ctx, preimageData)
}
......
......@@ -5,6 +5,7 @@ import (
"crypto/ecdsa"
"fmt"
"math/big"
"strings"
"testing"
"time"
......@@ -14,10 +15,8 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
keccakTypes "github.com/ethereum-optimism/optimism/op-challenger/game/keccak/types"
gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types"
"github.com/ethereum-optimism/optimism/op-e2e/bindings"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/transactions"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
preimage "github.com/ethereum-optimism/optimism/op-preimage"
"github.com/ethereum-optimism/optimism/op-service/errutil"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock"
......@@ -586,7 +585,11 @@ func (g *OutputGameHelper) StepFails(ctx context.Context, claimIdx int64, isAtta
_, _, err = transactions.SendTx(ctx, g.Client, candidate, g.PrivKey, transactions.WithReceiptFail())
err = errutil.TryAddRevertReason(err)
g.Require.Error(err, "Transaction should fail")
g.Require.Contains(err.Error(), "0xfb4e40dd", "Revert reason should be abi encoded ValidStep()")
validStepErr := "0xfb4e40dd"
invalidPrestateErr := "0x696550ff"
if !strings.Contains(err.Error(), validStepErr) && !strings.Contains(err.Error(), invalidPrestateErr) {
g.Require.Failf("Revert reason should be abi encoded ValidStep() or InvalidPrestate() but was: %v", err.Error())
}
}
// ResolveClaim resolves a single subgame
......@@ -649,28 +652,14 @@ func (g *OutputGameHelper) WaitForPreimageInOracle(ctx context.Context, data *ty
g.Require.NoErrorf(err, "Did not find preimage (%v) in oracle", common.Bytes2Hex(data.OracleKey))
}
func (g *OutputGameHelper) UploadPreimage(ctx context.Context, data *types.PreimageOracleData, privateKey *ecdsa.PrivateKey) {
func (g *OutputGameHelper) UploadPreimage(ctx context.Context, data *types.PreimageOracleData) {
oracle := g.oracle(ctx)
boundOracle, err := bindings.NewPreimageOracle(oracle.Addr(), g.Client)
g.Require.NoError(err)
var tx *gethtypes.Transaction
switch data.OracleKey[0] {
case byte(preimage.PrecompileKeyType):
tx, err = boundOracle.LoadPrecompilePreimagePart(
g.Opts,
new(big.Int).SetUint64(uint64(data.OracleOffset)),
data.GetPrecompileAddress(),
data.GetPrecompileInput(),
)
default:
tx, err = boundOracle.LoadKeccak256PreimagePart(g.Opts, new(big.Int).SetUint64(uint64(data.OracleOffset)), data.GetPreimageWithoutSize())
}
g.Require.NoError(err, "Failed to load preimage part")
_, err = wait.ForReceiptOK(ctx, g.Client, tx.Hash())
g.Require.NoError(err)
tx, err := oracle.AddGlobalDataTx(data)
g.Require.NoError(err, "Failed to create preimage upload tx")
transactions.RequireSendTx(g.T, ctx, g.Client, tx, g.PrivKey)
}
func (g *OutputGameHelper) oracle(ctx context.Context) *contracts.PreimageOracleContract {
func (g *OutputGameHelper) oracle(ctx context.Context) contracts.PreimageOracleContract {
oracle, err := g.Game.GetOracle(ctx)
g.Require.NoError(err, "Failed to create oracle contract")
return oracle
......
......@@ -7,6 +7,7 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/transactions"
"github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock"
"github.com/stretchr/testify/require"
)
......@@ -99,8 +100,13 @@ func (h *OutputHonestHelper) StepFails(ctx context.Context, claimIdx int64, isAt
// If we're defending, then the step will be from the trace to the next one
pos = pos.MoveRight()
}
prestate, proofData, _, err := h.correctTrace.GetStepData(ctx, game, claim, pos)
prestate, proofData, preimage, err := h.correctTrace.GetStepData(ctx, game, claim, pos)
h.require.NoError(err, "Get step data")
if preimage != nil {
tx, err := h.game.Game.UpdateOracleTx(ctx, uint64(claimIdx), preimage)
h.require.NoError(err)
transactions.RequireSendTx(h.t, ctx, h.game.Client, tx, h.game.PrivKey)
}
h.game.StepFails(ctx, claimIdx, isAttack, prestate, proofData)
}
......
......@@ -33,11 +33,11 @@ type Helper struct {
require *require.Assertions
client *ethclient.Client
privKey *ecdsa.PrivateKey
oracle *contracts.PreimageOracleContract
oracle contracts.PreimageOracleContract
uuidProvider atomic.Int64
}
func NewHelper(t *testing.T, privKey *ecdsa.PrivateKey, client *ethclient.Client, oracle *contracts.PreimageOracleContract) *Helper {
func NewHelper(t *testing.T, privKey *ecdsa.PrivateKey, client *ethclient.Client, oracle contracts.PreimageOracleContract) *Helper {
return &Helper{
t: t,
require: require.New(t),
......
......@@ -194,7 +194,7 @@ func TestOutputCannonDefendStep(t *testing.T) {
game.StartChallenger(ctx, "Challenger", challenger.WithPrivKey(sys.Cfg.Secrets.Alice))
correctTrace := game.CreateHonestActor(ctx, "sequencer", challenger.WithPrivKey(sys.Cfg.Secrets.Mallory))
correctTrace := game.CreateHonestActor(ctx, "sequencer", disputegame.WithPrivKey(sys.Cfg.Secrets.Mallory))
maxDepth := game.MaxDepth(ctx)
game.DefendClaim(ctx, outputRootClaim, func(claim *disputegame.ClaimHelper) *disputegame.ClaimHelper {
......@@ -410,7 +410,7 @@ func TestOutputCannonProposedOutputRootValid(t *testing.T) {
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
game := disputeGameFactory.StartOutputCannonGameWithCorrectRoot(ctx, "sequencer", 1)
correctTrace := game.CreateHonestActor(ctx, "sequencer", challenger.WithPrivKey(sys.Cfg.Secrets.Mallory))
correctTrace := game.CreateHonestActor(ctx, "sequencer", disputegame.WithPrivKey(sys.Cfg.Secrets.Mallory))
game.StartChallenger(ctx, "Challenger", challenger.WithPrivKey(sys.Cfg.Secrets.Alice))
......@@ -445,7 +445,7 @@ func TestOutputCannonPoisonedPostState(t *testing.T) {
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
// Root claim is dishonest
game := disputeGameFactory.StartOutputCannonGame(ctx, "sequencer", 1, common.Hash{0xaa})
correctTrace := game.CreateHonestActor(ctx, "sequencer", challenger.WithPrivKey(sys.Cfg.Secrets.Alice))
correctTrace := game.CreateHonestActor(ctx, "sequencer", disputegame.WithPrivKey(sys.Cfg.Secrets.Alice))
// Honest first attack at "honest" level
claim := correctTrace.AttackClaim(ctx, game.RootClaim(ctx))
......@@ -509,7 +509,7 @@ func TestDisputeOutputRootBeyondProposedBlock_ValidOutputRoot(t *testing.T) {
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
// Root claim is dishonest
game := disputeGameFactory.StartOutputCannonGameWithCorrectRoot(ctx, "sequencer", 1)
correctTrace := game.CreateHonestActor(ctx, "sequencer", challenger.WithPrivKey(sys.Cfg.Secrets.Alice))
correctTrace := game.CreateHonestActor(ctx, "sequencer", disputegame.WithPrivKey(sys.Cfg.Secrets.Alice))
// Start the honest challenger
game.StartChallenger(ctx, "Honest", challenger.WithPrivKey(sys.Cfg.Secrets.Bob))
......@@ -559,7 +559,7 @@ func TestDisputeOutputRootBeyondProposedBlock_InvalidOutputRoot(t *testing.T) {
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
// Root claim is dishonest
game := disputeGameFactory.StartOutputCannonGame(ctx, "sequencer", 1, common.Hash{0xaa})
correctTrace := game.CreateHonestActor(ctx, "sequencer", challenger.WithPrivKey(sys.Cfg.Secrets.Alice))
correctTrace := game.CreateHonestActor(ctx, "sequencer", disputegame.WithPrivKey(sys.Cfg.Secrets.Alice))
// Start the honest challenger
game.StartChallenger(ctx, "Honest", challenger.WithPrivKey(sys.Cfg.Secrets.Bob))
......@@ -610,7 +610,7 @@ func TestDisputeOutputRoot_ChangeClaimedOutputRoot(t *testing.T) {
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
// Root claim is dishonest
game := disputeGameFactory.StartOutputCannonGame(ctx, "sequencer", 1, common.Hash{0xaa})
correctTrace := game.CreateHonestActor(ctx, "sequencer", challenger.WithPrivKey(sys.Cfg.Secrets.Alice))
correctTrace := game.CreateHonestActor(ctx, "sequencer", disputegame.WithPrivKey(sys.Cfg.Secrets.Alice))
// Start the honest challenger
game.StartChallenger(ctx, "Honest", challenger.WithPrivKey(sys.Cfg.Secrets.Bob))
......@@ -700,7 +700,7 @@ func TestInvalidateUnsafeProposal(t *testing.T) {
// Root claim is _dishonest_ because the required data is not available on L1
game := disputeGameFactory.StartOutputCannonGameWithCorrectRoot(ctx, "sequencer", blockNum, disputegame.WithUnsafeProposal())
correctTrace := game.CreateHonestActor(ctx, "sequencer", challenger.WithPrivKey(sys.Cfg.Secrets.Alice))
correctTrace := game.CreateHonestActor(ctx, "sequencer", disputegame.WithPrivKey(sys.Cfg.Secrets.Alice))
// Start the honest challenger
game.StartChallenger(ctx, "Challenger", challenger.WithPrivKey(sys.Cfg.Secrets.Bob))
......@@ -762,7 +762,7 @@ func TestInvalidateProposalForFutureBlock(t *testing.T) {
// Root claim is _dishonest_ because the required data is not available on L1
game := disputeGameFactory.StartOutputCannonGame(ctx, "sequencer", farFutureBlockNum, common.Hash{0xaa}, disputegame.WithFutureProposal())
correctTrace := game.CreateHonestActor(ctx, "sequencer", challenger.WithPrivKey(sys.Cfg.Secrets.Alice))
correctTrace := game.CreateHonestActor(ctx, "sequencer", disputegame.WithPrivKey(sys.Cfg.Secrets.Alice))
// Start the honest challenger
game.StartChallenger(ctx, "Honest", challenger.WithPrivKey(sys.Cfg.Secrets.Bob))
......@@ -815,3 +815,98 @@ func TestInvalidateCorrectProposalFutureBlock(t *testing.T) {
game.WaitForGameStatus(ctx, gameTypes.GameStatusChallengerWon)
game.LogGameData(ctx)
}
func TestOutputCannonHonestSafeTraceExtension_ValidRoot(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background()
sys, l1Client := StartFaultDisputeSystem(t)
t.Cleanup(sys.Close)
// Wait for there to be there are safe L2 blocks past the claimed safe head that have data available on L1 within
// the commitment stored in the dispute game.
safeHeadNum := uint64(3)
require.NoError(t, wait.ForSafeBlock(ctx, sys.RollupClient("sequencer"), safeHeadNum))
// Create a dispute game with an honest claim
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
game := disputeGameFactory.StartOutputCannonGameWithCorrectRoot(ctx, "sequencer", safeHeadNum-1)
require.NotNil(t, game)
// Create a correct trace actor with an honest trace extending to L2 block #4
correctTrace := game.CreateHonestActor(ctx, "sequencer", disputegame.WithPrivKey(sys.Cfg.Secrets.Mallory))
// Create a correct trace actor with an honest trace extending to L2 block #5
// Notably, L2 block #5 is a valid block within the safe chain, and the data required to reproduce it
// will be committed to within the L1 head of the dispute game.
correctTracePlus1 := game.CreateHonestActor(ctx, "sequencer",
disputegame.WithPrivKey(sys.Cfg.Secrets.Mallory),
disputegame.WithClaimedL2BlockNumber(safeHeadNum))
// Start the honest challenger. They will defend the root claim.
game.StartChallenger(ctx, "Challenger", challenger.WithPrivKey(sys.Cfg.Secrets.Alice))
claim := game.RootClaim(ctx)
game.ChallengeClaim(ctx, claim, func(parent *disputegame.ClaimHelper) *disputegame.ClaimHelper {
// Have to disagree with the root claim - we're trying to invalidate a valid output root
if parent.IsRootClaim() {
return parent.Attack(ctx, common.Hash{0xdd})
}
return correctTracePlus1.CounterClaim(ctx, parent)
}, func(parentClaimIdx int64) {
correctTrace.StepFails(ctx, parentClaimIdx, true)
correctTrace.StepFails(ctx, parentClaimIdx, false)
correctTracePlus1.StepFails(ctx, parentClaimIdx, true)
correctTracePlus1.StepFails(ctx, parentClaimIdx, false)
})
game.LogGameData(ctx)
// Time travel past when the game will be resolvable.
sys.TimeTravelClock.AdvanceTime(game.MaxClockDuration(ctx))
require.NoError(t, wait.ForNextBlock(ctx, l1Client))
game.WaitForInactivity(ctx, 10, true)
game.LogGameData(ctx)
require.EqualValues(t, gameTypes.GameStatusDefenderWon, game.Status(ctx))
}
func TestOutputCannonHonestSafeTraceExtension_InvalidRoot(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background()
sys, l1Client := StartFaultDisputeSystem(t)
t.Cleanup(sys.Close)
// Wait for there to be there are safe L2 blocks past the claimed safe head that have data available on L1 within
// the commitment stored in the dispute game.
safeHeadNum := uint64(2)
require.NoError(t, wait.ForSafeBlock(ctx, sys.RollupClient("sequencer"), safeHeadNum))
// Create a dispute game with a dishonest claim @ L2 block #4
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
game := disputeGameFactory.StartOutputCannonGame(ctx, "sequencer", safeHeadNum-1, common.Hash{0xCA, 0xFE})
require.NotNil(t, game)
// Create a correct trace actor with an honest trace extending to L2 block #5
// Notably, L2 block #5 is a valid block within the safe chain, and the data required to reproduce it
// will be committed to within the L1 head of the dispute game.
correctTracePlus1 := game.CreateHonestActor(ctx, "sequencer",
disputegame.WithPrivKey(sys.Cfg.Secrets.Mallory),
disputegame.WithClaimedL2BlockNumber(safeHeadNum))
// Start the honest challenger. They will challenge the root claim.
game.StartChallenger(ctx, "Challenger", challenger.WithPrivKey(sys.Cfg.Secrets.Alice))
claim := game.RootClaim(ctx)
game.DefendClaim(ctx, claim, func(parent *disputegame.ClaimHelper) *disputegame.ClaimHelper {
return correctTracePlus1.CounterClaim(ctx, parent)
})
// Time travel past when the game will be resolvable.
sys.TimeTravelClock.AdvanceTime(game.MaxClockDuration(ctx))
require.NoError(t, wait.ForNextBlock(ctx, l1Client))
game.WaitForInactivity(ctx, 10, true)
game.LogGameData(ctx)
require.EqualValues(t, gameTypes.GameStatusChallengerWon, game.Status(ctx))
}
......@@ -24,6 +24,7 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/metrics"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/disputegame"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-service/client"
"github.com/ethereum-optimism/optimism/op-service/ioutil"
......@@ -35,14 +36,16 @@ func TestPrecompiles(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon)
// precompile test vectors copied from go-ethereum
tests := []struct {
name string
address common.Address
input []byte
name string
address common.Address
input []byte
accelerated bool
}{
{
name: "ecrecover",
address: common.BytesToAddress([]byte{0x01}),
input: common.FromHex("18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c000000000000000000000000000000000000000000000000000000000000001c73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549"),
name: "ecrecover",
address: common.BytesToAddress([]byte{0x01}),
input: common.FromHex("18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c000000000000000000000000000000000000000000000000000000000000001c73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549"),
accelerated: true,
},
{
name: "sha256",
......@@ -55,9 +58,10 @@ func TestPrecompiles(t *testing.T) {
input: common.FromHex("68656c6c6f20776f726c64"),
},
{
name: "bn256Pairing",
address: common.BytesToAddress([]byte{0x08}),
input: common.FromHex("1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa"),
name: "bn256Pairing",
address: common.BytesToAddress([]byte{0x08}),
input: common.FromHex("1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa"),
accelerated: true,
},
{
name: "blake2F",
......@@ -65,9 +69,10 @@ func TestPrecompiles(t *testing.T) {
input: common.FromHex("0000000048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"),
},
{
name: "kzgPointEvaluation",
address: common.BytesToAddress([]byte{0x0a}),
input: common.FromHex("01e798154708fe7789429634053cbf9f99b619f9f084048927333fce637f549b564c0a11a0f704f4fc3e8acfe0f8245f0ad1347b378fbf96e206da11a5d3630624d25032e67a7e6a4910df5834b8fe70e6bcfeeac0352434196bdf4b2485d5a18f59a8d2a1a625a17f3fea0fe5eb8c896db3764f3185481bc22f91b4aaffcca25f26936857bc3a7c2539ea8ec3a952b7873033e038326e87ed3e1276fd140253fa08e9fc25fb2d9a98527fc22a2c9612fbeafdad446cbc7bcdbdcd780af2c16a"),
name: "kzgPointEvaluation",
address: common.BytesToAddress([]byte{0x0a}),
input: common.FromHex("01e798154708fe7789429634053cbf9f99b619f9f084048927333fce637f549b564c0a11a0f704f4fc3e8acfe0f8245f0ad1347b378fbf96e206da11a5d3630624d25032e67a7e6a4910df5834b8fe70e6bcfeeac0352434196bdf4b2485d5a18f59a8d2a1a625a17f3fea0fe5eb8c896db3764f3185481bc22f91b4aaffcca25f26936857bc3a7c2539ea8ec3a952b7873033e038326e87ed3e1276fd140253fa08e9fc25fb2d9a98527fc22a2c9612fbeafdad446cbc7bcdbdcd780af2c16a"),
accelerated: true,
},
}
for _, test := range tests {
......@@ -134,6 +139,45 @@ func TestPrecompiles(t *testing.T) {
}
runCannon(t, ctx, sys, inputs, "sequencer")
})
t.Run("DisputePrecompile-"+test.name, func(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon)
if !test.accelerated {
t.Skipf("%v is not accelerated so no preimgae to upload", test.name)
}
ctx := context.Background()
sys, _ := StartFaultDisputeSystem(t, WithBlobBatches())
defer sys.Close()
l2Seq := sys.Clients["sequencer"]
aliceKey := sys.Cfg.Secrets.Alice
receipt := op_e2e.SendL2Tx(t, sys.Cfg, l2Seq, aliceKey, func(opts *op_e2e.TxOpts) {
opts.Gas = 1_000_000
opts.ToAddr = &test.address
opts.Nonce = 0
opts.Data = test.input
})
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys)
game := disputeGameFactory.StartOutputCannonGame(ctx, "sequencer", receipt.BlockNumber.Uint64(), common.Hash{0x01, 0xaa})
require.NotNil(t, game)
outputRootClaim := game.DisputeLastBlock(ctx)
game.LogGameData(ctx)
honestChallenger := game.StartChallenger(ctx, "HonestActor", challenger.WithPrivKey(sys.Cfg.Secrets.Alice))
// Wait for the honest challenger to dispute the outputRootClaim. This creates a root of an execution game that we challenge by coercing
// a step at a preimage trace index.
outputRootClaim = outputRootClaim.WaitForCounterClaim(ctx)
// Now the honest challenger is positioned as the defender of the execution game
// We then move to challenge it to induce a preimage load
preimageLoadCheck := game.CreateStepPreimageLoadCheck(ctx)
game.ChallengeToPreimageLoad(ctx, outputRootClaim, sys.Cfg.Secrets.Alice, utils.FirstPreimageLoadOfType("precompile"), preimageLoadCheck, false)
// The above method already verified the image was uploaded and step called successfully
// So we don't waste time resolving the game - that's tested elsewhere.
require.NoError(t, honestChallenger.Close())
})
}
}
......
......@@ -95,12 +95,12 @@ func (o *CachingOracle) GetBlob(ref eth.L1BlockRef, blobHash eth.IndexedBlobHash
return blob
}
func (o *CachingOracle) Precompile(address common.Address, input []byte) ([]byte, bool) {
func (o *CachingOracle) Precompile(address common.Address, input []byte, requiredGas uint64) ([]byte, bool) {
cacheKey := crypto.Keccak256Hash(append(address.Bytes(), input...))
if val, ok := o.pcmps.Get(cacheKey); ok {
return val.result, val.ok
}
res, ok := o.oracle.Precompile(address, input)
res, ok := o.oracle.Precompile(address, input, requiredGas)
o.pcmps.Add(cacheKey, precompileResult{res, ok})
return res, ok
}
package l1
import (
"encoding/binary"
"math/rand"
"testing"
......@@ -99,18 +100,21 @@ func TestCachingOracle_Precompile(t *testing.T) {
oracle := NewCachingOracle(stub)
input := []byte{0x01, 0x02, 0x03, 0x04}
requiredGas := uint64(100)
output := []byte{0x0a, 0x0b, 0x0c, 0x0d}
addr := common.Address{0x1}
key := crypto.Keccak256Hash(append(append(addr.Bytes(), binary.BigEndian.AppendUint64(nil, requiredGas)...), input...))
// Initial call retrieves from the stub
stub.PcmpResults[crypto.Keccak256Hash(append(addr.Bytes(), input...))] = output
actualResult, actualStatus := oracle.Precompile(addr, input)
stub.PcmpResults[key] = output
actualResult, actualStatus := oracle.Precompile(addr, input, requiredGas)
require.True(t, actualStatus)
require.EqualValues(t, output, actualResult)
// Later calls should retrieve from cache
delete(stub.PcmpResults, crypto.Keccak256Hash(append(addr.Bytes(), input...)))
actualResult, actualStatus = oracle.Precompile(addr, input)
delete(stub.PcmpResults, key)
actualResult, actualStatus = oracle.Precompile(addr, input, requiredGas)
require.True(t, actualStatus)
require.EqualValues(t, output, actualResult)
}
......@@ -13,6 +13,7 @@ const (
HintL1Receipts = "l1-receipts"
HintL1Blob = "l1-blob"
HintL1Precompile = "l1-precompile"
HintL1PrecompileV2 = "l1-precompile-v2"
)
type BlockHeaderHint common.Hash
......@@ -54,3 +55,11 @@ var _ preimage.Hint = PrecompileHint{}
func (l PrecompileHint) Hint() string {
return HintL1Precompile + " " + hexutil.Encode(l)
}
type PrecompileHintV2 []byte
var _ preimage.Hint = PrecompileHintV2{}
func (l PrecompileHintV2) Hint() string {
return HintL1PrecompileV2 + " " + hexutil.Encode(l)
}
......@@ -29,7 +29,7 @@ type Oracle interface {
GetBlob(ref eth.L1BlockRef, blobHash eth.IndexedBlobHash) *eth.Blob
// Precompile retrieves the result and success indicator of a precompile call for the given input.
Precompile(precompileAddress common.Address, input []byte) ([]byte, bool)
Precompile(precompileAddress common.Address, input []byte, requiredGas uint64) ([]byte, bool)
}
// PreimageOracle implements Oracle using by interfacing with the pure preimage.Oracle
......@@ -119,9 +119,10 @@ func (p *PreimageOracle) GetBlob(ref eth.L1BlockRef, blobHash eth.IndexedBlobHas
return &blob
}
func (p *PreimageOracle) Precompile(address common.Address, input []byte) ([]byte, bool) {
hintBytes := append(address.Bytes(), input...)
p.hint.Hint(PrecompileHint(hintBytes))
func (p *PreimageOracle) Precompile(address common.Address, input []byte, requiredGas uint64) ([]byte, bool) {
hintBytes := append(address.Bytes(), binary.BigEndian.AppendUint64(nil, requiredGas)...)
hintBytes = append(hintBytes, input...)
p.hint.Hint(PrecompileHintV2(hintBytes))
key := preimage.PrecompileKey(crypto.Keccak256Hash(hintBytes))
result := p.oracle.Get(key)
if len(result) == 0 { // must contain at least the status code
......
package test
import (
"encoding/binary"
"testing"
"github.com/ethereum-optimism/optimism/op-service/eth"
......@@ -75,8 +76,10 @@ func (o StubOracle) GetBlob(ref eth.L1BlockRef, blobHash eth.IndexedBlobHash) *e
return blob
}
func (o StubOracle) Precompile(addr common.Address, input []byte) ([]byte, bool) {
result, ok := o.PcmpResults[crypto.Keccak256Hash(append(addr.Bytes(), input...))]
func (o StubOracle) Precompile(addr common.Address, input []byte, requiredGas uint64) ([]byte, bool) {
arg := append(addr.Bytes(), binary.BigEndian.AppendUint64(nil, requiredGas)...)
arg = append(arg, input...)
result, ok := o.PcmpResults[crypto.Keccak256Hash(arg)]
if !ok {
o.t.Fatalf("unknown kzg point evaluation %x", input)
}
......
package l2
import (
"encoding/binary"
"math/big"
"testing"
......@@ -40,6 +41,12 @@ var (
blobPrecompileReturnValue = common.FromHex("000000000000000000000000000000000000000000000000000000000000100073eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001")
)
var (
ecRecoverRequiredGas uint64 = 3000
bn256PairingRequiredGas uint64 = 113000
kzgRequiredGas uint64 = 50_000
)
func TestInitialState(t *testing.T) {
blocks, chain := setupOracleBackedChain(t, 5)
head := blocks[5]
......@@ -200,28 +207,32 @@ func TestGetHeaderByNumber(t *testing.T) {
func TestPrecompileOracle(t *testing.T) {
tests := []struct {
name string
input []byte
target common.Address
result []byte
name string
input []byte
target common.Address
requiredGas uint64
result []byte
}{
{
name: "EcRecover",
input: ecRecoverInputData,
target: common.BytesToAddress([]byte{0x1}),
result: ecRecoverReturnValue,
name: "EcRecover",
input: ecRecoverInputData,
target: common.BytesToAddress([]byte{0x1}),
requiredGas: ecRecoverRequiredGas,
result: ecRecoverReturnValue,
},
{
name: "Bn256Pairing",
input: bn256PairingInputData,
target: common.BytesToAddress([]byte{0x8}),
result: bn256PairingReturnValue,
name: "Bn256Pairing",
input: bn256PairingInputData,
target: common.BytesToAddress([]byte{0x8}),
requiredGas: bn256PairingRequiredGas,
result: bn256PairingReturnValue,
},
{
name: "KZGPointEvaluation",
input: kzgInputData,
target: common.BytesToAddress([]byte{0xa}),
result: blobPrecompileReturnValue,
name: "KZGPointEvaluation",
input: kzgInputData,
target: common.BytesToAddress([]byte{0xa}),
requiredGas: kzgRequiredGas,
result: blobPrecompileReturnValue,
},
}
......@@ -234,9 +245,11 @@ func TestPrecompileOracle(t *testing.T) {
chainCfg, blocks, oracle := setupOracle(t, blockCount, headBlockNumber, true)
head := blocks[headBlockNumber].Hash()
stubOutput := eth.OutputV0{BlockHash: head}
precompileOracle := new(l2test.StubPrecompileOracle)
precompileOracle := l2test.NewStubPrecompileOracle(t)
arg := append(test.target.Bytes(), binary.BigEndian.AppendUint64(nil, test.requiredGas)...)
arg = append(arg, test.input...)
precompileOracle.Results = map[common.Hash]l2test.PrecompileResult{
crypto.Keccak256Hash(append(test.target.Bytes(), test.input...)): {Result: test.result, Ok: true},
crypto.Keccak256Hash(arg): {Result: test.result, Ok: true},
}
chain, err := NewOracleBackedL2Chain(logger, oracle, precompileOracle, chainCfg, common.Hash(eth.OutputRoot(&stubOutput)))
require.NoError(t, err)
......@@ -265,7 +278,7 @@ func setupOracleBackedChainWithLowerHead(t *testing.T, blockCount int, headBlock
chainCfg, blocks, oracle := setupOracle(t, blockCount, headBlockNumber, false)
head := blocks[headBlockNumber].Hash()
stubOutput := eth.OutputV0{BlockHash: head}
precompileOracle := new(l2test.StubPrecompileOracle)
precompileOracle := l2test.NewStubPrecompileOracle(t)
chain, err := NewOracleBackedL2Chain(logger, oracle, precompileOracle, chainCfg, common.Hash(eth.OutputRoot(&stubOutput)))
require.NoError(t, err)
return blocks, chain
......
......@@ -46,7 +46,7 @@ var (
// PrecompileOracle defines the high-level API used to retrieve the result of a precompile call
// The caller is expected to validate the input to the precompile call
type PrecompileOracle interface {
Precompile(address common.Address, input []byte) ([]byte, bool)
Precompile(address common.Address, input []byte, requiredGas uint64) ([]byte, bool)
}
func CreatePrecompileOverrides(precompileOracle PrecompileOracle) vm.PrecompileOverrides {
......@@ -104,7 +104,7 @@ func (c *ecrecoverOracle) Run(input []byte) ([]byte, error) {
// v needs to be at the end for libsecp256k1
// Modification note: below replaces the crypto.Ecrecover call
result, ok := c.Oracle.Precompile(ecrecoverPrecompileAddress, input)
result, ok := c.Oracle.Precompile(ecrecoverPrecompileAddress, input, c.RequiredGas(input))
if !ok {
return nil, errors.New("invalid ecrecover input")
}
......@@ -147,7 +147,7 @@ func (b *bn256PairingOracle) Run(input []byte) ([]byte, error) {
}
// Modification note: below replaces point verification and pairing checks
// Assumes both L2 and the L1 oracle have an identical range of valid points
result, ok := b.Oracle.Precompile(bn256PairingPrecompileAddress, input)
result, ok := b.Oracle.Precompile(bn256PairingPrecompileAddress, input, b.RequiredGas(input))
if !ok {
return nil, errors.New("invalid bn256Pairing check")
}
......@@ -214,7 +214,7 @@ func (b *kzgPointEvaluationOracle) Run(input []byte) ([]byte, error) {
copy(proof[:], input[144:])
// Modification note: below replaces the kzg4844.VerifyProof call
result, ok := b.Oracle.Precompile(kzgPointEvaluationPrecompileAddress, input)
result, ok := b.Oracle.Precompile(kzgPointEvaluationPrecompileAddress, input, b.RequiredGas(input))
if !ok {
return nil, fmt.Errorf("%w: invalid KZG point evaluation", errBlobVerifyKZGProof)
}
......
package test
import (
"encoding/binary"
"testing"
"github.com/ethereum-optimism/optimism/op-service/eth"
......@@ -130,15 +131,21 @@ type StubPrecompileOracle struct {
Calls int
}
func NewStubPrecompileOracle(t *testing.T) *StubPrecompileOracle {
return &StubPrecompileOracle{t: t, Results: make(map[common.Hash]PrecompileResult)}
}
type PrecompileResult struct {
Result []byte
Ok bool
}
func (o *StubPrecompileOracle) Precompile(address common.Address, input []byte) ([]byte, bool) {
result, ok := o.Results[crypto.Keccak256Hash(append(address.Bytes(), input...))]
func (o *StubPrecompileOracle) Precompile(address common.Address, input []byte, requiredGas uint64) ([]byte, bool) {
arg := append(address.Bytes(), binary.BigEndian.AppendUint64(nil, requiredGas)...)
arg = append(arg, input...)
result, ok := o.Results[crypto.Keccak256Hash(arg)]
if !ok {
o.t.Fatalf("no value for point evaluation %v", input)
o.t.Fatalf("no value for point evaluation %x required gas %v", input, requiredGas)
}
o.Calls++
return result.Result, result.Ok
......
......@@ -205,6 +205,36 @@ func (p *Prefetcher) prefetch(ctx context.Context, hint string) error {
return err
}
return p.kvStore.Put(preimage.PrecompileKey(inputHash).PreimageKey(), result)
case l1.HintL1PrecompileV2:
if len(hintBytes) < 28 {
return fmt.Errorf("invalid precompile hint: %x", hint)
}
precompileAddress := common.BytesToAddress(hintBytes[:20])
// requiredGas := hintBytes[20:28] - unused by the host. Since the client already validates gas requirements.
// The requiredGas is only used by the L1 PreimageOracle to enforce complete precompile execution.
// For extra safety, avoid accelerating unexpected precompiles
if !slices.Contains(acceleratedPrecompiles, precompileAddress) {
return fmt.Errorf("unsupported precompile address: %s", precompileAddress)
}
// NOTE: We use the precompiled contracts from Cancun because it's the only set that contains the addresses of all accelerated precompiles
// We assume the precompile Run function behavior does not change across EVM upgrades.
// As such, we must not rely on upgrade-specific behavior such as precompile.RequiredGas.
precompile := getPrecompiledContract(precompileAddress)
// KZG Point Evaluation precompile also verifies its input
result, err := precompile.Run(hintBytes[28:])
if err == nil {
result = append(precompileSuccess[:], result...)
} else {
result = append(precompileFailure[:], result...)
}
inputHash := crypto.Keccak256Hash(hintBytes)
// Put the input preimage so it can be loaded later
if err := p.kvStore.Put(preimage.Keccak256Key(inputHash).PreimageKey(), hintBytes); err != nil {
return err
}
return p.kvStore.Put(preimage.PrecompileKey(inputHash).PreimageKey(), result)
case l2.HintL2BlockHeader, l2.HintL2Transactions:
if len(hintBytes) != 32 {
return fmt.Errorf("invalid L2 header/tx hint: %x", hint)
......
......@@ -4,6 +4,7 @@ import (
"context"
"crypto/sha256"
"encoding/binary"
"fmt"
"math/rand"
"testing"
......@@ -25,6 +26,11 @@ import (
"github.com/ethereum-optimism/optimism/op-service/testutils"
)
var (
ecRecoverInput = common.FromHex("18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c000000000000000000000000000000000000000000000000000000000000001c73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549")
kzgPointEvalInput = common.FromHex("01e798154708fe7789429634053cbf9f99b619f9f084048927333fce637f549b564c0a11a0f704f4fc3e8acfe0f8245f0ad1347b378fbf96e206da11a5d3630624d25032e67a7e6a4910df5834b8fe70e6bcfeeac0352434196bdf4b2485d5a18f59a8d2a1a625a17f3fea0fe5eb8c896db3764f3185481bc22f91b4aaffcca25f26936857bc3a7c2539ea8ec3a952b7873033e038326e87ed3e1276fd140253fa08e9fc25fb2d9a98527fc22a2c9612fbeafdad446cbc7bcdbdcd780af2c16a")
)
func TestNoHint(t *testing.T) {
t.Run("NotFound", func(t *testing.T) {
prefetcher, _, _, _, _ := createPrefetcher(t)
......@@ -221,9 +227,6 @@ func TestFetchL1Blob(t *testing.T) {
}
func TestFetchPrecompileResult(t *testing.T) {
ecRecoverInput := common.FromHex("18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c000000000000000000000000000000000000000000000000000000000000001c73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549")
kzgPointEvalInput := common.FromHex("01e798154708fe7789429634053cbf9f99b619f9f084048927333fce637f549b564c0a11a0f704f4fc3e8acfe0f8245f0ad1347b378fbf96e206da11a5d3630624d25032e67a7e6a4910df5834b8fe70e6bcfeeac0352434196bdf4b2485d5a18f59a8d2a1a625a17f3fea0fe5eb8c896db3764f3185481bc22f91b4aaffcca25f26936857bc3a7c2539ea8ec3a952b7873033e038326e87ed3e1276fd140253fa08e9fc25fb2d9a98527fc22a2c9612fbeafdad446cbc7bcdbdcd780af2c16a")
failure := []byte{0}
success := []byte{1}
......@@ -239,6 +242,18 @@ func TestFetchPrecompileResult(t *testing.T) {
input: ecRecoverInput,
result: append(success, common.FromHex("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b")...),
},
{
name: "KzgPointEvaluation-Valid",
addr: common.BytesToAddress([]byte{0xa}),
input: kzgPointEvalInput,
result: append(success, common.FromHex("000000000000000000000000000000000000000000000000000000000000100073eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001")...),
},
{
name: "KzgPointEvaluation-Invalid",
addr: common.BytesToAddress([]byte{0xa}),
input: []byte{0x0},
result: failure,
},
{
name: "Bn256Pairing-Valid",
addr: common.BytesToAddress([]byte{0x8}),
......@@ -251,17 +266,88 @@ func TestFetchPrecompileResult(t *testing.T) {
input: []byte{0x1},
result: failure,
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
prefetcher, _, _, _, _ := createPrefetcher(t)
oracle := newLegacyPrecompileOracle(asOracleFn(t, prefetcher), asHinter(t, prefetcher))
result, ok := oracle.Precompile(test.addr, test.input)
require.Equal(t, test.result[0] == 1, ok)
require.EqualValues(t, test.result[1:], result)
key := crypto.Keccak256Hash(append(test.addr.Bytes(), test.input...))
val, err := prefetcher.kvStore.Get(preimage.Keccak256Key(key).PreimageKey())
require.NoError(t, err)
require.NotEmpty(t, val)
val, err = prefetcher.kvStore.Get(preimage.PrecompileKey(key).PreimageKey())
require.NoError(t, err)
require.EqualValues(t, test.result, val)
})
}
t.Run("Already Known", func(t *testing.T) {
input := []byte("test input")
addr := common.BytesToAddress([]byte{0x1})
result := []byte{0x1}
prefetcher, _, _, _, kv := createPrefetcher(t)
err := kv.Put(preimage.PrecompileKey(crypto.Keccak256Hash(append(addr.Bytes(), input...))).PreimageKey(), append([]byte{1}, result...))
require.NoError(t, err)
oracle := newLegacyPrecompileOracle(asOracleFn(t, prefetcher), asHinter(t, prefetcher))
actualResult, status := oracle.Precompile(addr, input)
require.EqualValues(t, result, actualResult)
require.True(t, status)
})
}
func TestFetchPrecompileResultV2(t *testing.T) {
failure := []byte{0}
success := []byte{1}
tests := []struct {
name string
addr common.Address
input []byte
requiredGas uint64
result []byte
}{
{
name: "EcRecover-Valid",
addr: common.BytesToAddress([]byte{0x1}),
input: ecRecoverInput,
requiredGas: 3000,
result: append(success, common.FromHex("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b")...),
},
{
name: "KzgPointEvaluation-Valid",
addr: common.BytesToAddress([]byte{0xa}),
input: kzgPointEvalInput,
result: append(success, common.FromHex("000000000000000000000000000000000000000000000000000000000000100073eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001")...),
name: "Bn256Pairing-Valid",
addr: common.BytesToAddress([]byte{0x8}),
input: []byte{}, // empty is valid
requiredGas: 6000,
result: append(success, common.FromHex("0000000000000000000000000000000000000000000000000000000000000001")...),
},
{
name: "KzgPointEvaluation-Invalid",
addr: common.BytesToAddress([]byte{0xa}),
input: []byte{0x0},
result: failure,
name: "Bn256Pairing-Invalid",
addr: common.BytesToAddress([]byte{0x8}),
input: []byte{0x1},
requiredGas: 6000,
result: failure,
},
{
name: "KzgPointEvaluation-Valid",
addr: common.BytesToAddress([]byte{0xa}),
input: kzgPointEvalInput,
requiredGas: 50_000,
result: append(success, common.FromHex("000000000000000000000000000000000000000000000000000000000000100073eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001")...),
},
{
name: "KzgPointEvaluation-Invalid",
addr: common.BytesToAddress([]byte{0xa}),
input: []byte{0x0},
requiredGas: 50_000,
result: failure,
},
}
for _, test := range tests {
......@@ -270,11 +356,11 @@ func TestFetchPrecompileResult(t *testing.T) {
prefetcher, _, _, _, _ := createPrefetcher(t)
oracle := l1.NewPreimageOracle(asOracleFn(t, prefetcher), asHinter(t, prefetcher))
result, ok := oracle.Precompile(test.addr, test.input)
result, ok := oracle.Precompile(test.addr, test.input, test.requiredGas)
require.Equal(t, test.result[0] == 1, ok)
require.EqualValues(t, test.result[1:], result)
key := crypto.Keccak256Hash(append(test.addr.Bytes(), test.input...))
key := crypto.Keccak256Hash(append(append(test.addr.Bytes(), binary.BigEndian.AppendUint64(nil, test.requiredGas)...), test.input...))
val, err := prefetcher.kvStore.Get(preimage.Keccak256Key(key).PreimageKey())
require.NoError(t, err)
require.NotEmpty(t, val)
......@@ -287,19 +373,35 @@ func TestFetchPrecompileResult(t *testing.T) {
t.Run("Already Known", func(t *testing.T) {
input := []byte("test input")
requiredGas := uint64(3000)
addr := common.BytesToAddress([]byte{0x1})
result := []byte{0x1}
prefetcher, _, _, _, kv := createPrefetcher(t)
err := kv.Put(preimage.PrecompileKey(crypto.Keccak256Hash(append(addr.Bytes(), input...))).PreimageKey(), append([]byte{1}, result...))
keyArg := append(addr.Bytes(), binary.BigEndian.AppendUint64(nil, requiredGas)...)
keyArg = append(keyArg, input...)
err := kv.Put(preimage.PrecompileKey(crypto.Keccak256Hash(keyArg)).PreimageKey(), append([]byte{1}, result...))
require.NoError(t, err)
oracle := l1.NewPreimageOracle(asOracleFn(t, prefetcher), asHinter(t, prefetcher))
actualResult, status := oracle.Precompile(addr, input)
actualResult, status := oracle.Precompile(addr, input, requiredGas)
require.EqualValues(t, actualResult, result)
require.True(t, status)
})
}
func TestUnsupportedPrecompile(t *testing.T) {
prefetcher, _, _, _, _ := createPrefetcher(t)
oracleFn := func(t *testing.T, prefetcher *Prefetcher) preimage.OracleFn {
return func(key preimage.Key) []byte {
_, err := prefetcher.GetPreimage(context.Background(), key.PreimageKey())
require.ErrorContains(t, err, "unsupported precompile address")
return []byte{1}
}
}
oracle := newLegacyPrecompileOracle(oracleFn(t, prefetcher), asHinter(t, prefetcher))
oracle.Precompile(common.HexToAddress("0xdead"), nil)
}
func TestRestrictedPrecompileContracts(t *testing.T) {
for _, addr := range acceleratedPrecompiles {
require.NotNil(t, getPrecompiledContract(addr))
......@@ -596,3 +698,28 @@ func assertReceiptsEqual(t *testing.T, expectedRcpt types.Receipts, actualRcpt t
require.Equal(t, expected, actual)
}
}
// legacyOracleImpl is a wrapper around the new preimage.Oracle interface that uses the legacy preimage hint API.
// It's used to test backwards-compatibility with clients using legacy preimage hints.
type legacyPrecompileOracle struct {
oracle preimage.Oracle
hint preimage.Hinter
}
func newLegacyPrecompileOracle(raw preimage.Oracle, hint preimage.Hinter) *legacyPrecompileOracle {
return &legacyPrecompileOracle{
oracle: raw,
hint: hint,
}
}
func (o *legacyPrecompileOracle) Precompile(address common.Address, input []byte) ([]byte, bool) {
hintBytes := append(address.Bytes(), input...)
o.hint.Hint(l1.PrecompileHint(hintBytes))
key := preimage.PrecompileKey(crypto.Keccak256Hash(hintBytes))
result := o.oracle.Get(key)
if len(result) == 0 { // must contain at least the status code
panic(fmt.Errorf("unexpected precompile oracle behavior, got result: %x", result))
}
return result[1:], result[0] == 1
}
......@@ -5,7 +5,7 @@ SCRIPTS_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
COMPAT_DIR="${SCRIPTS_DIR}/../temp/compat"
TESTNAME="${1?Must specify compat file to run}"
BASEURL="${2:-https://github.com/ethereum-optimism/chain-test-data/releases/download/2024-03-14.3}"
BASEURL="${2:-https://github.com/ethereum-optimism/chain-test-data/releases/download/2024-08-02}"
URL="${BASEURL}/${TESTNAME}.tar.bz"
......
......@@ -56,7 +56,7 @@ func (c *expectedCall) Matches(rpcMethod string, args ...interface{}) error {
return fmt.Errorf("expected input to have at least 4 bytes but was %v", len(data))
}
if !slices.Equal(c.abiMethod.ID, data[:4]) {
return fmt.Errorf("expected abi method ID %x but was %x", c.abiMethod.ID, data[:4])
return fmt.Errorf("expected abi method ID %x but was %v", c.abiMethod.ID, data[:4])
}
if !slices.Equal(c.packedArgs, data[4:]) {
return fmt.Errorf("expected args %x but was %x", c.packedArgs, data[4:])
......
......@@ -59,7 +59,7 @@ func (r *RpcStub) findExpectedCall(rpcMethod string, args ...interface{}) Expect
if err := call.Matches(rpcMethod, args...); err == nil {
return call
} else {
matchResults += fmt.Sprintf("%v: %v", call, err)
matchResults += fmt.Sprintf("%v: %v\n", call, err)
}
}
require.Failf(r.t, "No matching expected calls.", matchResults)
......
......@@ -41,7 +41,7 @@
"requiredProtocolVersion": "0x0000000000000000000000000000000000000004000000000000000000000001",
"recommendedProtocolVersion": "0x0000000000000000000000000000000000000004000000000000000000000001",
"fundDevAccounts": false,
"faultGameAbsolutePrestate": "0x0385c3f8ee78491001d92b90b07d0cf387b7b52ab9b83b4d87c994e92cf823ba",
"faultGameAbsolutePrestate": "0x030de10d9da911a2b180ecfae2aeaba8758961fc28262ce989458c6f9a547922",
"faultGameMaxDepth": 73,
"faultGameClockExtension": 10800,
"faultGameMaxClockDuration": 302400,
......
......@@ -208,6 +208,32 @@ library ChainAssertions {
}
}
/// @notice Asserts that the permissioned DelayedWETH is setup correctly
function checkPermissionedDelayedWETH(
Types.ContractSet memory _contracts,
DeployConfig _cfg,
bool _isProxy,
address _expectedOwner
)
internal
view
{
console.log("Running chain assertions on the permissioned DelayedWETH");
DelayedWETH weth = DelayedWETH(payable(_contracts.PermissionedDelayedWETH));
// Check that the contract is initialized
assertSlotValueIsOne({ _contractAddress: address(weth), _slot: 0, _offset: 0 });
if (_isProxy) {
require(weth.owner() == _expectedOwner);
require(weth.delay() == _cfg.faultGameWithdrawalDelay());
require(weth.config() == SuperchainConfig(_contracts.SuperchainConfig));
} else {
require(weth.owner() == _expectedOwner);
require(weth.delay() == _cfg.faultGameWithdrawalDelay());
}
}
/// @notice Asserts that the L2OutputOracle is setup correctly
function checkL2OutputOracle(
Types.ContractSet memory _contracts,
......
......@@ -151,6 +151,7 @@ contract Deploy is Deployer {
L2OutputOracle: mustGetAddress("L2OutputOracleProxy"),
DisputeGameFactory: mustGetAddress("DisputeGameFactoryProxy"),
DelayedWETH: mustGetAddress("DelayedWETHProxy"),
PermissionedDelayedWETH: mustGetAddress("PermissionedDelayedWETHProxy"),
AnchorStateRegistry: mustGetAddress("AnchorStateRegistryProxy"),
OptimismMintableERC20Factory: mustGetAddress("OptimismMintableERC20FactoryProxy"),
OptimismPortal: mustGetAddress("OptimismPortalProxy"),
......@@ -170,6 +171,7 @@ contract Deploy is Deployer {
L2OutputOracle: getAddress("L2OutputOracleProxy"),
DisputeGameFactory: getAddress("DisputeGameFactoryProxy"),
DelayedWETH: getAddress("DelayedWETHProxy"),
PermissionedDelayedWETH: getAddress("PermissionedDelayedWETHProxy"),
AnchorStateRegistry: getAddress("AnchorStateRegistryProxy"),
OptimismMintableERC20Factory: getAddress("OptimismMintableERC20FactoryProxy"),
OptimismPortal: getAddress("OptimismPortalProxy"),
......@@ -369,6 +371,7 @@ contract Deploy is Deployer {
deployERC1967Proxy("DisputeGameFactoryProxy");
deployERC1967Proxy("L2OutputOracleProxy");
deployERC1967Proxy("DelayedWETHProxy");
deployERC1967Proxy("PermissionedDelayedWETHProxy");
deployERC1967Proxy("AnchorStateRegistryProxy");
transferAddressManagerOwnership(); // to the ProxyAdmin
......@@ -413,6 +416,7 @@ contract Deploy is Deployer {
initializeL2OutputOracle();
initializeDisputeGameFactory();
initializeDelayedWETH();
initializePermissionedDelayedWETH();
initializeAnchorStateRegistry();
}
......@@ -959,10 +963,34 @@ contract Deploy is Deployer {
});
}
function initializePermissionedDelayedWETH() public broadcast {
console.log("Upgrading and initializing permissioned DelayedWETH proxy");
address delayedWETHProxy = mustGetAddress("PermissionedDelayedWETHProxy");
address delayedWETH = mustGetAddress("DelayedWETH");
address superchainConfigProxy = mustGetAddress("SuperchainConfigProxy");
_upgradeAndCallViaSafe({
_proxy: payable(delayedWETHProxy),
_implementation: delayedWETH,
_innerCallData: abi.encodeCall(DelayedWETH.initialize, (msg.sender, SuperchainConfig(superchainConfigProxy)))
});
string memory version = DelayedWETH(payable(delayedWETHProxy)).version();
console.log("DelayedWETH version: %s", version);
ChainAssertions.checkPermissionedDelayedWETH({
_contracts: _proxiesUnstrict(),
_cfg: cfg,
_isProxy: true,
_expectedOwner: msg.sender
});
}
function initializeAnchorStateRegistry() public broadcast {
console.log("Upgrading and initializing AnchorStateRegistry proxy");
address anchorStateRegistryProxy = mustGetAddress("AnchorStateRegistryProxy");
address anchorStateRegistry = mustGetAddress("AnchorStateRegistry");
SuperchainConfig superchainConfig = SuperchainConfig(mustGetAddress("SuperchainConfigProxy"));
AnchorStateRegistry.StartingAnchorRoot[] memory roots = new AnchorStateRegistry.StartingAnchorRoot[](5);
roots[0] = AnchorStateRegistry.StartingAnchorRoot({
......@@ -1004,7 +1032,7 @@ contract Deploy is Deployer {
_upgradeAndCallViaSafe({
_proxy: payable(anchorStateRegistryProxy),
_implementation: anchorStateRegistry,
_innerCallData: abi.encodeCall(AnchorStateRegistry.initialize, (roots))
_innerCallData: abi.encodeCall(AnchorStateRegistry.initialize, (roots, superchainConfig))
});
string memory version = AnchorStateRegistry(payable(anchorStateRegistryProxy)).version();
......@@ -1348,6 +1376,25 @@ contract Deploy is Deployer {
ChainAssertions.checkDelayedWETH({ _contracts: _proxies(), _cfg: cfg, _isProxy: true, _expectedOwner: safe });
}
/// @notice Transfer ownership of the permissioned DelayedWETH contract to the final system owner
function transferPermissionedDelayedWETHOwnership() public broadcast {
console.log("Transferring permissioned DelayedWETH ownership to Safe");
DelayedWETH weth = DelayedWETH(mustGetAddress("PermissionedDelayedWETHProxy"));
address owner = weth.owner();
address safe = mustGetAddress("SystemOwnerSafe");
if (owner != safe) {
weth.transferOwnership(safe);
console.log("DelayedWETH ownership transferred to Safe at: %s", safe);
}
ChainAssertions.checkPermissionedDelayedWETH({
_contracts: _proxies(),
_cfg: cfg,
_isProxy: true,
_expectedOwner: safe
});
}
/// @notice Loads the mips absolute prestate from the prestate-proof for devnets otherwise
/// from the config.
function loadMipsAbsolutePrestate() internal returns (Claim mipsAbsolutePrestate_) {
......@@ -1401,7 +1448,7 @@ contract Deploy is Deployer {
function setPermissionedCannonFaultGameImplementation(bool _allowUpgrade) public broadcast {
console.log("Setting Cannon PermissionedDisputeGame implementation");
DisputeGameFactory factory = DisputeGameFactory(mustGetAddress("DisputeGameFactoryProxy"));
DelayedWETH weth = DelayedWETH(mustGetAddress("DelayedWETHProxy"));
DelayedWETH weth = DelayedWETH(mustGetAddress("PermissionedDelayedWETHProxy"));
// Set the Cannon FaultDisputeGame implementation in the factory.
_setFaultGameImplementation({
......@@ -1449,6 +1496,7 @@ contract Deploy is Deployer {
DelayedWETH weth = DelayedWETH(mustGetAddress("DelayedWETHProxy"));
Claim outputAbsolutePrestate = Claim.wrap(bytes32(cfg.faultGameAbsolutePrestate()));
PreimageOracle fastOracle = new PreimageOracle(cfg.preimageOracleMinProposalSize(), 0);
_setFaultGameImplementation({
_factory: factory,
_allowUpgrade: _allowUpgrade,
......@@ -1457,7 +1505,7 @@ contract Deploy is Deployer {
weth: weth,
gameType: GameTypes.FAST,
absolutePrestate: outputAbsolutePrestate,
faultVm: IBigStepper(new AlphabetVM(outputAbsolutePrestate, PreimageOracle(mustGetAddress("PreimageOracle")))),
faultVm: IBigStepper(new AlphabetVM(outputAbsolutePrestate, fastOracle)),
// The max depth for the alphabet trace is always 3. Add 1 because split depth is fully inclusive.
maxGameDepth: cfg.faultGameSplitDepth() + 3 + 1,
maxClockDuration: Duration.wrap(0) // Resolvable immediately
......
......@@ -92,6 +92,8 @@ contract FPACOPS is Deploy, StdAssertions {
function initializeAnchorStateRegistryProxy() internal broadcast {
console.log("Initializing AnchorStateRegistryProxy with AnchorStateRegistry.");
address superchainConfigProxy = mustGetAddress("SuperchainConfigProxy");
SuperchainConfig superchainConfig = SuperchainConfig(superchainConfigProxy);
AnchorStateRegistry.StartingAnchorRoot[] memory roots = new AnchorStateRegistry.StartingAnchorRoot[](2);
roots[0] = AnchorStateRegistry.StartingAnchorRoot({
......@@ -111,7 +113,8 @@ contract FPACOPS is Deploy, StdAssertions {
address asrProxy = mustGetAddress("AnchorStateRegistryProxy");
Proxy(payable(asrProxy)).upgradeToAndCall(
mustGetAddress("AnchorStateRegistry"), abi.encodeCall(AnchorStateRegistry.initialize, (roots))
mustGetAddress("AnchorStateRegistry"),
abi.encodeCall(AnchorStateRegistry.initialize, (roots, superchainConfig))
);
}
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Proxy } from "src/universal/Proxy.sol";
import { IDisputeGame } from "src/dispute/interfaces/IDisputeGame.sol";
import { AnchorStateRegistry, IAnchorStateRegistry } from "src/dispute/AnchorStateRegistry.sol";
import { IDelayedWETH } from "src/dispute/interfaces/IDelayedWETH.sol";
import { StdAssertions } from "forge-std/StdAssertions.sol";
import "src/dispute/lib/Types.sol";
import "scripts/deploy/Deploy.s.sol";
/// @notice Deploys new implementations of the FaultDisputeGame contract and its dependencies
/// assuming that the DisputeGameFactory contract does not need to be modified. Assumes
/// that the System Owner will update the DisputeGameFactory to point to these new
/// contracts at a later point in time.
contract FPACOPS2 is Deploy, StdAssertions {
////////////////////////////////////////////////////////////////
// ENTRYPOINTS //
////////////////////////////////////////////////////////////////
/// @notice Deploys an updated FP system with new FaultDisputeGame contracts and new
/// DelayedWETH contracts. Deploys a new implementation of the
/// AnchorStateRegistry. Does not deploy a new DisputeGameFactory. System
/// Owner is responsible for updating implementations later.
/// @param _proxyAdmin Address of the ProxyAdmin contract to transfer ownership to.
/// @param _systemOwnerSafe Address of the SystemOwner.
/// @param _superchainConfigProxy Address of the SuperchainConfig proxy contract.
/// @param _disputeGameFactoryProxy Address of the DisputeGameFactory proxy contract.
/// @param _anchorStateRegistryProxy Address of the AnchorStateRegistry proxy contract.
function deployFPAC2(
address _proxyAdmin,
address _systemOwnerSafe,
address _superchainConfigProxy,
address _disputeGameFactoryProxy,
address _anchorStateRegistryProxy
)
public
{
console.log("Deploying updated FP contracts.");
// Prank required deployments.
prankDeployment("ProxyAdmin", msg.sender);
prankDeployment("SystemOwnerSafe", msg.sender);
prankDeployment("SuperchainConfigProxy", _superchainConfigProxy);
prankDeployment("DisputeGameFactoryProxy", _disputeGameFactoryProxy);
prankDeployment("AnchorStateRegistryProxy", _anchorStateRegistryProxy);
// Deploy the proxies.
deployERC1967Proxy("DelayedWETHProxy");
deployERC1967Proxy("PermissionedDelayedWETHProxy");
// Deploy implementations.
deployDelayedWETH();
deployAnchorStateRegistry();
deployPreimageOracle();
deployMips();
// Initialize the proxies.
initializeDelayedWETHProxy();
initializePermissionedDelayedWETHProxy();
// Deploy the new game implementations.
deployCannonDisputeGame();
deployPermissionedDisputeGame();
// Transfer ownership of DelayedWETH to ProxyAdmin.
transferWethOwnershipFinal({ _proxyAdmin: _proxyAdmin, _systemOwnerSafe: _systemOwnerSafe });
transferPermissionedWETHOwnershipFinal({ _proxyAdmin: _proxyAdmin, _systemOwnerSafe: _systemOwnerSafe });
// Run post-deployment assertions.
postDeployAssertions({ _proxyAdmin: _proxyAdmin, _systemOwnerSafe: _systemOwnerSafe });
// Print overview.
printConfigReview();
}
////////////////////////////////////////////////////////////////
// HELPERS //
////////////////////////////////////////////////////////////////
/// @notice Deploys the standard Cannon version of the FaultDisputeGame.
function deployCannonDisputeGame() internal broadcast {
console.log("Deploying CannonFaultDisputeGame implementation");
save(
"CannonFaultDisputeGame",
address(
new FaultDisputeGame({
_gameType: GameTypes.CANNON,
_absolutePrestate: loadMipsAbsolutePrestate(),
_maxGameDepth: cfg.faultGameMaxDepth(),
_splitDepth: cfg.faultGameSplitDepth(),
_clockExtension: Duration.wrap(uint64(cfg.faultGameClockExtension())),
_maxClockDuration: Duration.wrap(uint64(cfg.faultGameMaxClockDuration())),
_vm: IBigStepper(mustGetAddress("Mips")),
_weth: DelayedWETH(mustGetAddress("DelayedWETHProxy")),
_anchorStateRegistry: AnchorStateRegistry(mustGetAddress("AnchorStateRegistryProxy")),
_l2ChainId: cfg.l2ChainID()
})
)
);
}
/// @notice Deploys the PermissionedDisputeGame.
function deployPermissionedDisputeGame() internal broadcast {
console.log("Deploying PermissionedDisputeGame implementation");
save(
"PermissionedDisputeGame",
address(
new PermissionedDisputeGame({
_gameType: GameTypes.PERMISSIONED_CANNON,
_absolutePrestate: loadMipsAbsolutePrestate(),
_maxGameDepth: cfg.faultGameMaxDepth(),
_splitDepth: cfg.faultGameSplitDepth(),
_clockExtension: Duration.wrap(uint64(cfg.faultGameClockExtension())),
_maxClockDuration: Duration.wrap(uint64(cfg.faultGameMaxClockDuration())),
_vm: IBigStepper(mustGetAddress("Mips")),
_weth: DelayedWETH(mustGetAddress("PermissionedDelayedWETHProxy")),
_anchorStateRegistry: AnchorStateRegistry(mustGetAddress("AnchorStateRegistryProxy")),
_l2ChainId: cfg.l2ChainID(),
_proposer: cfg.l2OutputOracleProposer(),
_challenger: cfg.l2OutputOracleChallenger()
})
)
);
}
/// @notice Initializes the DelayedWETH proxy.
function initializeDelayedWETHProxy() internal broadcast {
console.log("Initializing DelayedWETHProxy with DelayedWETH.");
address wethProxy = mustGetAddress("DelayedWETHProxy");
address superchainConfigProxy = mustGetAddress("SuperchainConfigProxy");
Proxy(payable(wethProxy)).upgradeToAndCall(
mustGetAddress("DelayedWETH"),
abi.encodeCall(DelayedWETH.initialize, (msg.sender, SuperchainConfig(superchainConfigProxy)))
);
}
/// @notice Initializes the permissioned DelayedWETH proxy.
function initializePermissionedDelayedWETHProxy() internal broadcast {
console.log("Initializing permissioned DelayedWETHProxy with DelayedWETH.");
address wethProxy = mustGetAddress("PermissionedDelayedWETHProxy");
address superchainConfigProxy = mustGetAddress("SuperchainConfigProxy");
Proxy(payable(wethProxy)).upgradeToAndCall(
mustGetAddress("DelayedWETH"),
abi.encodeCall(DelayedWETH.initialize, (msg.sender, SuperchainConfig(superchainConfigProxy)))
);
}
/// @notice Transfers admin rights of the `DelayedWETHProxy` to the `ProxyAdmin` and sets the
/// `DelayedWETH` owner to the `SystemOwnerSafe`.
function transferWethOwnershipFinal(address _proxyAdmin, address _systemOwnerSafe) internal broadcast {
console.log("Transferring ownership of DelayedWETHProxy");
DelayedWETH weth = DelayedWETH(mustGetAddress("DelayedWETHProxy"));
// Transfer the ownership of the DelayedWETH to the SystemOwnerSafe.
weth.transferOwnership(_systemOwnerSafe);
// Transfer the admin rights of the DelayedWETHProxy to the ProxyAdmin.
Proxy prox = Proxy(payable(address(weth)));
prox.changeAdmin(_proxyAdmin);
}
/// @notice Transfers admin rights of the permissioned `DelayedWETHProxy` to the `ProxyAdmin`
/// and sets the `DelayedWETH` owner to the `SystemOwnerSafe`.
function transferPermissionedWETHOwnershipFinal(address _proxyAdmin, address _systemOwnerSafe) internal broadcast {
console.log("Transferring ownership of permissioned DelayedWETHProxy");
DelayedWETH weth = DelayedWETH(mustGetAddress("PermissionedDelayedWETHProxy"));
// Transfer the ownership of the DelayedWETH to the SystemOwnerSafe.
weth.transferOwnership(_systemOwnerSafe);
// Transfer the admin rights of the DelayedWETHProxy to the ProxyAdmin.
Proxy prox = Proxy(payable(address(weth)));
prox.changeAdmin(_proxyAdmin);
}
/// @notice Checks that the deployed system is configured correctly.
function postDeployAssertions(address _proxyAdmin, address _systemOwnerSafe) internal view {
Types.ContractSet memory contracts = _proxiesUnstrict();
// Ensure that `useFaultProofs` is set to `true`.
assertTrue(cfg.useFaultProofs());
// Verify that the DGF is owned by the ProxyAdmin.
address dgfProxyAddr = mustGetAddress("DisputeGameFactoryProxy");
assertEq(address(uint160(uint256(vm.load(dgfProxyAddr, Constants.PROXY_OWNER_ADDRESS)))), _proxyAdmin);
// Verify that DelayedWETH is owned by the ProxyAdmin.
address wethProxyAddr = mustGetAddress("DelayedWETHProxy");
assertEq(address(uint160(uint256(vm.load(wethProxyAddr, Constants.PROXY_OWNER_ADDRESS)))), _proxyAdmin);
// Verify that permissioned DelayedWETH is owned by the ProxyAdmin.
address soyWethProxyAddr = mustGetAddress("PermissionedDelayedWETHProxy");
assertEq(address(uint160(uint256(vm.load(soyWethProxyAddr, Constants.PROXY_OWNER_ADDRESS)))), _proxyAdmin);
// Run standard assertions for DGF and DelayedWETH.
ChainAssertions.checkDisputeGameFactory(contracts, _systemOwnerSafe);
ChainAssertions.checkDelayedWETH(contracts, cfg, true, _systemOwnerSafe);
ChainAssertions.checkPermissionedDelayedWETH(contracts, cfg, true, _systemOwnerSafe);
// Verify PreimageOracle configuration.
PreimageOracle oracle = PreimageOracle(mustGetAddress("PreimageOracle"));
assertEq(oracle.minProposalSize(), cfg.preimageOracleMinProposalSize());
assertEq(oracle.challengePeriod(), cfg.preimageOracleChallengePeriod());
// Verify MIPS configuration.
MIPS mips = MIPS(mustGetAddress("Mips"));
assertEq(address(mips.oracle()), address(oracle));
// Grab ASR
AnchorStateRegistry asr = AnchorStateRegistry(mustGetAddress("AnchorStateRegistryProxy"));
// Verify FaultDisputeGame configuration.
address gameAddr = mustGetAddress("CannonFaultDisputeGame");
FaultDisputeGame gameImpl = FaultDisputeGame(payable(gameAddr));
assertEq(gameImpl.maxGameDepth(), cfg.faultGameMaxDepth());
assertEq(gameImpl.splitDepth(), cfg.faultGameSplitDepth());
assertEq(gameImpl.clockExtension().raw(), cfg.faultGameClockExtension());
assertEq(gameImpl.maxClockDuration().raw(), cfg.faultGameMaxClockDuration());
assertEq(gameImpl.absolutePrestate().raw(), bytes32(cfg.faultGameAbsolutePrestate()));
assertEq(address(gameImpl.weth()), wethProxyAddr);
assertEq(address(gameImpl.anchorStateRegistry()), address(asr));
assertEq(address(gameImpl.vm()), address(mips));
// Verify security override yoke configuration.
address soyGameAddr = mustGetAddress("PermissionedDisputeGame");
PermissionedDisputeGame soyGameImpl = PermissionedDisputeGame(payable(soyGameAddr));
assertEq(soyGameImpl.proposer(), cfg.l2OutputOracleProposer());
assertEq(soyGameImpl.challenger(), cfg.l2OutputOracleChallenger());
assertEq(soyGameImpl.maxGameDepth(), cfg.faultGameMaxDepth());
assertEq(soyGameImpl.splitDepth(), cfg.faultGameSplitDepth());
assertEq(soyGameImpl.clockExtension().raw(), cfg.faultGameClockExtension());
assertEq(soyGameImpl.maxClockDuration().raw(), cfg.faultGameMaxClockDuration());
assertEq(soyGameImpl.absolutePrestate().raw(), bytes32(cfg.faultGameAbsolutePrestate()));
assertEq(address(soyGameImpl.weth()), soyWethProxyAddr);
assertEq(address(soyGameImpl.anchorStateRegistry()), address(asr));
assertEq(address(soyGameImpl.vm()), address(mips));
}
/// @notice Prints a review of the fault proof configuration section of the deploy config.
function printConfigReview() internal view {
console.log(unicode"📖 FaultDisputeGame Config Overview (chainid: %d)", block.chainid);
console.log(" 0. Use Fault Proofs: %s", cfg.useFaultProofs() ? "true" : "false");
console.log(" 1. Absolute Prestate: %x", cfg.faultGameAbsolutePrestate());
console.log(" 2. Max Depth: %d", cfg.faultGameMaxDepth());
console.log(" 3. Output / Execution split Depth: %d", cfg.faultGameSplitDepth());
console.log(" 4. Clock Extension (seconds): %d", cfg.faultGameClockExtension());
console.log(" 5. Max Clock Duration (seconds): %d", cfg.faultGameMaxClockDuration());
console.log(" 6. L2 Genesis block number: %d", cfg.faultGameGenesisBlock());
console.log(" 7. L2 Genesis output root: %x", uint256(cfg.faultGameGenesisOutputRoot()));
console.log(" 8. Proof Maturity Delay (seconds): ", cfg.proofMaturityDelaySeconds());
console.log(" 9. Dispute Game Finality Delay (seconds): ", cfg.disputeGameFinalityDelaySeconds());
console.log(" 10. Respected Game Type: ", cfg.respectedGameType());
console.log(" 11. Preimage Oracle Min Proposal Size (bytes): ", cfg.preimageOracleMinProposalSize());
console.log(" 12. Preimage Oracle Challenge Period (seconds): ", cfg.preimageOracleChallengePeriod());
}
}
......@@ -23,4 +23,9 @@ cannon-prestate: # Generate the cannon prestate, and tar the `op-program` + `can
.PHONY: deploy-fresh
deploy-fresh: cannon-prestate # Deploy a fresh version of the FPAC contracts. Pass `--broadcast` to send to the network.
forge script FPACOPS.sol --sig "deployFPAC(address,address)" $(proxy-admin) $(system-owner-safe) --chain $(chain) -vvv $(args)
forge script FPACOPS.s.sol --sig "deployFPAC(address,address,address)" $(proxy-admin) $(system-owner-safe) $(superchain-config-proxy) --chain $(chain) -vvv $(args)
# TODO: Convert this whole file to a justfile
.PHONY: deploy-upgrade
deploy-upgrade: cannon-prestate # Deploy upgraded FP contracts. Pass `--broadcast` to send to the network.
forge script FPACOPS2.s.sol --sig "deployFPAC2(address,address,address,address,address)" $(proxy-admin) $(system-owner-safe) $(superchain-config-proxy) $(dispute-game-factory-proxy) $(anchor-state-registry-proxy) --chain $(chain) -vvv $(args)
......@@ -9,6 +9,7 @@ library Types {
address L2OutputOracle;
address DisputeGameFactory;
address DelayedWETH;
address PermissionedDelayedWETH;
address AnchorStateRegistry;
address OptimismMintableERC20Factory;
address OptimismPortal;
......
......@@ -128,8 +128,8 @@
"sourceCodeHash": "0xbe200a6cb297a3ca1a7d174a9c886e3f17eb8edf617ad014a2ac4f6c2e2ac7f1"
},
"src/Safe/DeputyGuardianModule.sol": {
"initCodeHash": "0x433eb7488e613a51c7ff05a76bbecf47f5beac8b8614f5c50001f99e39ae7ed2",
"sourceCodeHash": "0x5b415dc432a83fb1d5c41585539245997c62acb6bd77c489bf57e9b59be5f983"
"initCodeHash": "0x5e0e2089fa737bfeeeff66cb84f4c0a90cd42f9ef4d4814b4850094f48c2a391",
"sourceCodeHash": "0x6ad81146f59f35f17e1ea432e902de3ef6fc84a4aedcbe0593f5997af6835018"
},
"src/Safe/LivenessGuard.sol": {
"initCodeHash": "0xf54289de5cef7ba0044e0d63310937fa231d6528aac91e13e531c845af42afac",
......@@ -140,32 +140,32 @@
"sourceCodeHash": "0x3ff4a3f21202478935412d47fd5ef7f94a170402ddc50e5c062013ce5544c83f"
},
"src/cannon/MIPS.sol": {
"initCodeHash": "0xfc2381da4ad202f1ff7b97776be0e9a510ef3c36c0f557cbada1a0943f376e62",
"sourceCodeHash": "0x5f5d13be282305b2947079cbf8f01e750e5c88a2b7a7a7267e79cba3ee4616fa"
"initCodeHash": "0x826aa41a3f37c3ef6613be21eb9bb275bdf0a48d2196dffc56f494b68b32a156",
"sourceCodeHash": "0x10cd9132b6c9f45af6b7f11ccc50bb889c62105bdb556bc7fb4100b6136e37df"
},
"src/cannon/MIPS2.sol": {
"initCodeHash": "0xd75b7541ca736dff03b1fa7116a9835f97bc82507287bf90f3dd739299f5aa03",
"sourceCodeHash": "0x115bd6a4c4d77ed210dfd468675b409fdae9f79b932063c138f0765ba9063462"
"initCodeHash": "0xbb425bd1c3cad13a77f5c9676b577606e2f8f320687739f529b257a042f58d85",
"sourceCodeHash": "0xe66f19942947f53ccd658b94c1ef6db39e947419d4ec7436067c6cc44452ff73"
},
"src/cannon/PreimageOracle.sol": {
"initCodeHash": "0xe5db668fe41436f53995e910488c7c140766ba8745e19743773ebab508efd090",
"sourceCodeHash": "0x7c8b26cd263f6be144bace1f3faf0ec9265df0efb68ac34fa1fa7df7f608ab42"
"initCodeHash": "0x967d730bb1b10a36ee625179734cccd6b6826ce480bad0419272663c460603bd",
"sourceCodeHash": "0xa73ce9635a75395c09e00e383f0c9072308813971c8f0dffe445dd9310f7007a"
},
"src/dispute/AnchorStateRegistry.sol": {
"initCodeHash": "0x0305c21e50829b9e07d43358d8c2c82f1449534c90d4391400d46e76d0503a49",
"sourceCodeHash": "0x56b069b33d080c2a45ee6fd340e5c5824ab4dc866eadb5b481b9026ebb12aa7c"
"initCodeHash": "0xe064c2d66f48d71a91db81a9f54ea819bc75f90e98efbd3efca1e460a16d8cc5",
"sourceCodeHash": "0xb01e484637783b0e4f1e0f20d073659c21ac8232442cc506886720b3ec736cd9"
},
"src/dispute/DisputeGameFactory.sol": {
"initCodeHash": "0x7a7cb8f2c95df2f9afb3ce9eaefe4a6f997ccce7ed8ffda5d425a65a2474a792",
"sourceCodeHash": "0x918c395ac5d77357f2551616aad0613e68893862edd14e554623eb16ee6ba148"
},
"src/dispute/FaultDisputeGame.sol": {
"initCodeHash": "0x5ea5b544b8d7b32f55f7864c25a2443a5db363ffd1c66e0799cbc7bccaf98526",
"sourceCodeHash": "0xa0d373c969b78752aefb66b56807490e16ce0d09c8514b485b3d2df29bf8d514"
"initCodeHash": "0xe0b6dae6078d1e7237240ab3c589055190ff4a4bb16280dcbf3919e062ad8f84",
"sourceCodeHash": "0xea69f63d4df701e9dfb73b85692c9a62b8a5819b3f473889c9da3734131b9738"
},
"src/dispute/weth/DelayedWETH.sol": {
"initCodeHash": "0xb9bbe005874922cd8f499e7a0a092967cfca03e012c1e41912b0c77481c71777",
"sourceCodeHash": "0x87d00995773d34cc28e81559f4cc5f25890d924df285ec6e9e01b5277f52a9dc"
"initCodeHash": "0x305074302172657578c3fff485fb2115d608834a3c1447d9a957e4baf55a982c",
"sourceCodeHash": "0xb3a260564b82992fac71ad21be01ebe7eaae6855f66cafbd4a0b21f53853e17e"
},
"src/legacy/DeployerWhitelist.sol": {
"initCodeHash": "0x8de80fb23b26dd9d849f6328e56ea7c173cd9e9ce1f05c9beea559d1720deb3d",
......
......@@ -77,6 +77,11 @@
"internalType": "struct AnchorStateRegistry.StartingAnchorRoot[]",
"name": "_startingAnchorRoots",
"type": "tuple[]"
},
{
"internalType": "contract SuperchainConfig",
"name": "_superchainConfig",
"type": "address"
}
],
"name": "initialize",
......@@ -84,6 +89,32 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract IFaultDisputeGame",
"name": "_game",
"type": "address"
}
],
"name": "setAnchorState",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "superchainConfig",
"outputs": [
{
"internalType": "contract SuperchainConfig",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "tryUpdateAnchorState",
......@@ -116,5 +147,20 @@
],
"name": "Initialized",
"type": "event"
},
{
"inputs": [],
"name": "InvalidGameStatus",
"type": "error"
},
{
"inputs": [],
"name": "Unauthorized",
"type": "error"
},
{
"inputs": [],
"name": "UnregisteredGame",
"type": "error"
}
]
\ No newline at end of file
......@@ -71,6 +71,24 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract AnchorStateRegistry",
"name": "_registry",
"type": "address"
},
{
"internalType": "contract IFaultDisputeGame",
"name": "_game",
"type": "address"
}
],
"name": "setAnchorState",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
......
......@@ -963,6 +963,11 @@
"name": "IncorrectBondAmount",
"type": "error"
},
{
"inputs": [],
"name": "InvalidChallengePeriod",
"type": "error"
},
{
"inputs": [],
"name": "InvalidClockExtension",
......
......@@ -1004,6 +1004,11 @@
"name": "IncorrectBondAmount",
"type": "error"
},
{
"inputs": [],
"name": "InvalidChallengePeriod",
"type": "error"
},
{
"inputs": [],
"name": "InvalidClockExtension",
......
......@@ -54,6 +54,19 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "PRECOMPILE_CALL_RESERVED_GAS",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
......@@ -378,6 +391,11 @@
"name": "_precompile",
"type": "address"
},
{
"internalType": "uint64",
"name": "_requiredGas",
"type": "uint64"
},
{
"internalType": "bytes",
"name": "_input",
......@@ -833,6 +851,11 @@
"name": "AlreadyFinalized",
"type": "error"
},
{
"inputs": [],
"name": "AlreadyInitialized",
"type": "error"
},
{
"inputs": [],
"name": "BadProposal",
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -19,5 +19,12 @@
"offset": 0,
"slot": "1",
"type": "mapping(GameType => struct OutputRoot)"
},
{
"bytes": "20",
"label": "superchainConfig",
"offset": 0,
"slot": "2",
"type": "contract SuperchainConfig"
}
]
\ No newline at end of file
......@@ -4,11 +4,13 @@ pragma solidity 0.8.15;
import { GnosisSafe as Safe } from "safe-contracts/GnosisSafe.sol";
import { Enum } from "safe-contracts/common/Enum.sol";
import { IFaultDisputeGame } from "src/dispute/interfaces/IFaultDisputeGame.sol";
import { SuperchainConfig } from "src/L1/SuperchainConfig.sol";
import { OptimismPortal2 } from "src/L1/OptimismPortal2.sol";
import { IDisputeGame } from "src/dispute/interfaces/IDisputeGame.sol";
import { ISemver } from "src/universal/ISemver.sol";
import { Unauthorized } from "src/libraries/PortalErrors.sol";
import { AnchorStateRegistry } from "src/dispute/AnchorStateRegistry.sol";
import "src/dispute/lib/Types.sol";
......@@ -43,8 +45,8 @@ contract DeputyGuardianModule is ISemver {
address internal immutable DEPUTY_GUARDIAN;
/// @notice Semantic version.
/// @custom:semver 1.1.0
string public constant version = "1.1.0";
/// @custom:semver 2.0.0
string public constant version = "2.0.0";
// Constructor to initialize the Safe and baseModule instances
constructor(Safe _safe, SuperchainConfig _superchainConfig, address _deputyGuardian) {
......@@ -108,6 +110,22 @@ contract DeputyGuardianModule is ISemver {
emit Unpaused();
}
/// @notice Calls the Security Council Safe's `execTransactionFromModuleReturnData()`, with the arguments
/// necessary to call `setAnchorState()` on the `AnchorStateRegistry` contract.
/// Only the deputy guardian can call this function.
/// @param _registry The `AnchorStateRegistry` contract instance.
/// @param _game The `IFaultDisputeGame` contract instance.
function setAnchorState(AnchorStateRegistry _registry, IFaultDisputeGame _game) external {
_onlyDeputyGuardian();
bytes memory data = abi.encodeCall(AnchorStateRegistry.setAnchorState, (_game));
(bool success, bytes memory returnData) =
SAFE.execTransactionFromModuleReturnData(address(_registry), 0, data, Enum.Operation.Call);
if (!success) {
revert ExecutionFailed(string(returnData));
}
}
/// @notice Calls the Security Council Safe's `execTransactionFromModuleReturnData()`, with the arguments
/// necessary to call `blacklistDisputeGame()` on the `OptimismPortal2` contract.
/// Only the deputy guardian can call this function.
......
......@@ -44,8 +44,8 @@ contract MIPS is ISemver {
}
/// @notice The semantic version of the MIPS contract.
/// @custom:semver 1.0.1
string public constant version = "1.1.0-beta.6";
/// @custom:semver 1.1.0
string public constant version = "1.1.0";
/// @notice The preimage oracle contract.
IPreimageOracle internal immutable ORACLE;
......@@ -98,6 +98,14 @@ contract MIPS is ISemver {
from, to := copyMem(from, to, 8) // step
from := add(from, 32) // offset to registers
// Verify that the value of exited is valid (0 or 1)
if gt(exited, 1) {
// revert InvalidExitedValue();
let ptr := mload(0x40)
mstore(ptr, shl(224, 0x0136cc76))
revert(ptr, 0x04)
}
// Copy registers
for { let i := 0 } lt(i, 32) { i := add(i, 1) } { from, to := copyMem(from, to, 4) }
......@@ -149,7 +157,7 @@ contract MIPS is ISemver {
(v0, v1, state.heap) = sys.handleSysMmap(a0, a1, state.heap);
} else if (syscall_no == sys.SYS_BRK) {
// brk: Returns a fixed address for the program break at 0x40000000
v0 = sys.BRK_START;
v0 = sys.PROGRAM_BREAK;
} else if (syscall_no == sys.SYS_CLONE) {
// clone (not supported) returns 1
v0 = 1;
......@@ -243,10 +251,24 @@ contract MIPS is ISemver {
c, m := putField(c, m, 4) // heap
c, m := putField(c, m, 1) // exitCode
c, m := putField(c, m, 1) // exited
let exited := mload(sub(m, 32))
c, m := putField(c, m, 8) // step
// Verify that the value of exited is valid (0 or 1)
if gt(exited, 1) {
// revert InvalidExitedValue();
let ptr := mload(0x40)
mstore(ptr, shl(224, 0x0136cc76))
revert(ptr, 0x04)
}
// Compiler should have done this already
if iszero(eq(mload(m), add(m, 32))) {
// expected registers offset check
revert(0, 0)
}
// Unpack register calldata into memory
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) }
}
......
......@@ -51,8 +51,8 @@ contract MIPS2 is ISemver {
}
/// @notice The semantic version of the MIPS2 contract.
/// @custom:semver 0.0.2-beta
string public constant version = "1.0.0-beta.3";
/// @custom:semver 1.0.0-beta.4
string public constant version = "1.0.0-beta.4";
/// @notice The preimage oracle contract.
IPreimageOracle internal immutable ORACLE;
......@@ -256,7 +256,7 @@ contract MIPS2 is ISemver {
(v0, v1, state.heap) = sys.handleSysMmap(a0, a1, state.heap);
} else if (syscall_no == sys.SYS_BRK) {
// brk: Returns a fixed address for the program break at 0x40000000
v0 = sys.BRK_START;
v0 = sys.PROGRAM_BREAK;
} else if (syscall_no == sys.SYS_CLONE) {
if (sys.VALID_SYS_CLONE_FLAGS != a0) {
state.exited = true;
......
......@@ -27,10 +27,12 @@ contract PreimageOracle is IPreimageOracle, ISemver {
uint256 public constant KECCAK_TREE_DEPTH = 16;
/// @notice The maximum number of keccak blocks that can fit into the merkle tree.
uint256 public constant MAX_LEAF_COUNT = 2 ** KECCAK_TREE_DEPTH - 1;
/// @notice The reserved gas for precompile call setup.
uint256 public constant PRECOMPILE_CALL_RESERVED_GAS = 100_000;
/// @notice The semantic version of the Preimage Oracle contract.
/// @custom:semver 1.0.0
string public constant version = "1.0.0";
/// @custom:semver 1.1.2
string public constant version = "1.1.2";
////////////////////////////////////////////////////////////////
// Authorized Preimage Parts //
......@@ -90,6 +92,11 @@ contract PreimageOracle is IPreimageOracle, ISemver {
MIN_LPP_SIZE_BYTES = _minProposalSize;
CHALLENGE_PERIOD = _challengePeriod;
// Make sure challenge period fits within uint64 so that it can safely be used within the
// FaultDisputeGame contract to compute clock extensions. Adding this check is simpler than
// changing the existing contract ABI.
require(_challengePeriod <= type(uint64).max, "challenge period too large");
// Compute hashes in empty sparse Merkle tree. The first hash is not set, and kept as zero as the identity.
for (uint256 height = 0; height < KECCAK_TREE_DEPTH - 1; height++) {
zeroHashes[height + 1] = keccak256(abi.encodePacked(zeroHashes[height], zeroHashes[height]));
......@@ -131,7 +138,7 @@ contract PreimageOracle is IPreimageOracle, ISemver {
key_ = PreimageKeyLib.localizeIdent(_ident, _localContext);
// Revert if the given part offset is not within bounds.
if (_partOffset > _size + 8 || _size > 32) {
if (_partOffset >= _size + 8 || _size > 32) {
revert PartOffsetOOB();
}
......@@ -332,7 +339,14 @@ contract PreimageOracle is IPreimageOracle, ISemver {
}
/// @inheritdoc IPreimageOracle
function loadPrecompilePreimagePart(uint256 _partOffset, address _precompile, bytes calldata _input) external {
function loadPrecompilePreimagePart(
uint256 _partOffset,
address _precompile,
uint64 _requiredGas,
bytes calldata _input
)
external
{
bytes32 res;
bytes32 key;
bytes32 part;
......@@ -341,21 +355,32 @@ contract PreimageOracle is IPreimageOracle, ISemver {
// we leave solidity slots 0x40 and 0x60 untouched, and everything after as scratch-memory.
let ptr := 0x80
// copy precompile address and input into memory
// len(sig) + len(_partOffset) + address-offset-in-slot
calldatacopy(ptr, 48, 20)
calldatacopy(add(20, ptr), _input.offset, _input.length)
// copy precompile address, requiredGas, and input into memory to compute the key
mstore(ptr, shl(96, _precompile))
mstore(add(ptr, 20), shl(192, _requiredGas))
calldatacopy(add(28, ptr), _input.offset, _input.length)
// compute the hash
let h := keccak256(ptr, add(20, _input.length))
let h := keccak256(ptr, add(28, _input.length))
// mask out prefix byte, replace with type 6 byte
key := or(and(h, not(shl(248, 0xFF))), shl(248, 0x06))
// Check if the precompile call has at least the required gas.
// This assumes there are no further memory expansion costs until after the staticall on the precompile
// Also assumes that the gas expended in setting up the staticcall is less than PRECOMPILE_CALL_RESERVED_GAS
// require(gas() >= (requiredGas * 64 / 63) + reservedGas)
if lt(mul(gas(), 63), add(mul(_requiredGas, 64), mul(PRECOMPILE_CALL_RESERVED_GAS, 63))) {
// Store "NotEnoughGas()"
mstore(0, 0xdd629f86)
revert(0x1c, 4)
}
// Call the precompile to get the result.
// SAFETY: Given the above gas check, the staticall cannot fail due to insufficient gas.
res :=
staticcall(
gas(), // forward all gas
_precompile,
add(20, ptr), // input ptr
add(28, ptr), // input ptr
_input.length,
0x0, // Unused as we don't copy anything
0x00 // don't copy anything
......@@ -429,6 +454,10 @@ contract PreimageOracle is IPreimageOracle, ISemver {
// Initialize the proposal metadata.
LPPMetaData metaData = proposalMetadata[msg.sender][_uuid];
// Revert if the proposal has already been initialized. 0-size preimages are *not* allowed.
if (metaData.claimedSize() != 0) revert AlreadyInitialized();
proposalMetadata[msg.sender][_uuid] = metaData.setPartOffset(_partOffset).setClaimedSize(_claimedSize);
proposals.push(LargePreimageProposalKeys(msg.sender, _uuid));
......@@ -484,7 +513,7 @@ contract PreimageOracle is IPreimageOracle, ISemver {
let inputPtr := add(input, 0x20)
// The input length must be a multiple of 136 bytes
// The input lenth / 136 must be equal to the number of state commitments.
// The input length / 136 must be equal to the number of state commitments.
if or(mod(inputLen, 136), iszero(eq(_stateCommitments.length, div(inputLen, 136)))) {
// Store "InvalidInputSize()" error selector
mstore(0x00, 0x7b1daf1)
......@@ -653,6 +682,9 @@ contract PreimageOracle is IPreimageOracle, ISemver {
// Check if the proposal was countered.
if (metaData.countered()) revert BadProposal();
// Check if the proposal has been finalized at all.
if (metaData.timestamp() == 0) revert ActiveProposal();
// Check if the challenge period has passed since the proposal was finalized.
if (block.timestamp - metaData.timestamp() <= CHALLENGE_PERIOD) revert ActiveProposal();
......
......@@ -4,6 +4,10 @@ pragma solidity 0.8.15;
/// @title IPreimageOracle
/// @notice Interface for a preimage oracle.
interface IPreimageOracle {
/// @notice Returns the length of the large preimage proposal challenge period.
/// @return challengePeriod_ The length of the challenge period in seconds.
function challengePeriod() external view returns (uint256 challengePeriod_);
/// @notice Reads a preimage from the oracle.
/// @param _key The key of the preimage to read.
/// @param _offset The offset of the preimage to read.
......@@ -75,6 +79,13 @@ interface IPreimageOracle {
/// The preimage key is `6 ++ keccak256(precompile ++ input)[1:]`.
/// @param _partOffset The offset of the precompile result being loaded.
/// @param _precompile The precompile address
/// @param _requiredGas The gas required to fully execute an L1 precompile.
/// @param _input The input to the precompile call.
function loadPrecompilePreimagePart(uint256 _partOffset, address _precompile, bytes calldata _input) external;
function loadPrecompilePreimagePart(
uint256 _partOffset,
address _precompile,
uint64 _requiredGas,
bytes calldata _input
)
external;
}
......@@ -4,6 +4,9 @@ pragma solidity 0.8.15;
/// @notice Thrown when a passed part offset is out of bounds.
error PartOffsetOOB();
/// @notice Thrown when insufficient gas is provided when loading precompile preimages.
error NotEnoughGas();
/// @notice Thrown when a merkle proof fails to verify.
error InvalidProof();
......@@ -37,6 +40,9 @@ error BadProposal();
/// @notice Thrown when attempting to add leaves to a preimage proposal that has not been initialized.
error NotInitialized();
/// @notice Thrown when attempting to re-initialize an existing large preimage proposal.
error AlreadyInitialized();
/// @notice Thrown when the caller of a function is not an EOA.
error NotEOA();
......@@ -45,3 +51,6 @@ error InsufficientBond();
/// @notice Thrown when a bond transfer fails.
error BondTransferFailed();
/// @notice Thrown when the value of the exited boolean is not 0 or 1.
error InvalidExitedValue();
......@@ -227,7 +227,10 @@ library MIPSInstructions {
}
// srav
else if (_fun == 0x07) {
return signExtend(_rt >> _rs, 32 - _rs);
// shamt here is different than the typical shamt which comes from the
// instruction itself, here it comes from the rs register
uint32 shamt = _rs & 0x1F;
return signExtend(_rt >> shamt, 32 - shamt);
}
// functs in range [0x8, 0x1b] are handled specially by other functions
// Explicitly enumerate each funct in range to reduce code diff against Go Vm
......
......@@ -99,7 +99,8 @@ library MIPSSyscalls {
uint32 internal constant SCHED_QUANTUM = 100_000;
/// @notice Start of the data segment.
uint32 internal constant BRK_START = 0x40000000;
uint32 internal constant PROGRAM_BREAK = 0x40000000;
uint32 internal constant HEAP_END = 0x60000000;
// SYS_CLONE flags
uint32 internal constant CLONE_VM = 0x100;
......@@ -175,6 +176,12 @@ library MIPSSyscalls {
if (_a0 == 0) {
v0_ = _heap;
newHeap_ += sz;
// Fail if new heap exceeds memory limit, newHeap overflows to low memory, or sz overflows
if (newHeap_ > HEAP_END || newHeap_ < _heap || sz < _a1) {
v0_ = SYS_ERROR_SIGNAL;
v1_ = EINVAL;
return (v0_, v1_, _heap);
}
} else {
v0_ = _a0;
}
......
......@@ -8,8 +8,11 @@ import { IAnchorStateRegistry } from "src/dispute/interfaces/IAnchorStateRegistr
import { IFaultDisputeGame } from "src/dispute/interfaces/IFaultDisputeGame.sol";
import { IDisputeGame } from "src/dispute/interfaces/IDisputeGame.sol";
import { IDisputeGameFactory } from "src/dispute/interfaces/IDisputeGameFactory.sol";
import { SuperchainConfig } from "src/L1/SuperchainConfig.sol";
import "src/dispute/lib/Types.sol";
import { Unauthorized } from "src/libraries/errors/CommonErrors.sol";
import { UnregisteredGame, InvalidGameStatus } from "src/dispute/lib/Errors.sol";
/// @title AnchorStateRegistry
/// @notice The AnchorStateRegistry is a contract that stores the latest "anchor" state for each available
......@@ -24,8 +27,8 @@ contract AnchorStateRegistry is Initializable, IAnchorStateRegistry, ISemver {
}
/// @notice Semantic version.
/// @custom:semver 1.0.0
string public constant version = "1.0.0";
/// @custom:semver 2.0.0
string public constant version = "2.0.0";
/// @notice DisputeGameFactory address.
IDisputeGameFactory internal immutable DISPUTE_GAME_FACTORY;
......@@ -33,21 +36,30 @@ contract AnchorStateRegistry is Initializable, IAnchorStateRegistry, ISemver {
/// @inheritdoc IAnchorStateRegistry
mapping(GameType => OutputRoot) public anchors;
/// @notice Address of the SuperchainConfig contract.
SuperchainConfig public superchainConfig;
/// @param _disputeGameFactory DisputeGameFactory address.
constructor(IDisputeGameFactory _disputeGameFactory) {
DISPUTE_GAME_FACTORY = _disputeGameFactory;
// Initialize the implementation with an empty array of starting anchor roots.
initialize(new StartingAnchorRoot[](0));
_disableInitializers();
}
/// @notice Initializes the contract.
/// @param _startingAnchorRoots An array of starting anchor roots.
function initialize(StartingAnchorRoot[] memory _startingAnchorRoots) public initializer {
/// @param _superchainConfig The address of the SuperchainConfig contract.
function initialize(
StartingAnchorRoot[] memory _startingAnchorRoots,
SuperchainConfig _superchainConfig
)
public
initializer
{
for (uint256 i = 0; i < _startingAnchorRoots.length; i++) {
StartingAnchorRoot memory startingAnchorRoot = _startingAnchorRoots[i];
anchors[startingAnchorRoot.gameType] = startingAnchorRoot.outputRoot;
}
superchainConfig = _superchainConfig;
}
/// @inheritdoc IAnchorStateRegistry
......@@ -67,10 +79,7 @@ contract AnchorStateRegistry is Initializable, IAnchorStateRegistry, ISemver {
DISPUTE_GAME_FACTORY.games({ _gameType: gameType, _rootClaim: rootClaim, _extraData: extraData });
// Must be a valid game.
require(
address(factoryRegisteredGame) == address(game),
"AnchorStateRegistry: fault dispute game not registered with factory"
);
if (address(factoryRegisteredGame) != address(game)) revert UnregisteredGame();
// No need to update anything if the anchor state is already newer.
if (game.l2BlockNumber() <= anchors[gameType].l2BlockNumber) {
......@@ -85,4 +94,27 @@ contract AnchorStateRegistry is Initializable, IAnchorStateRegistry, ISemver {
// Actually update the anchor state.
anchors[gameType] = OutputRoot({ l2BlockNumber: game.l2BlockNumber(), root: Hash.wrap(game.rootClaim().raw()) });
}
/// @inheritdoc IAnchorStateRegistry
function setAnchorState(IFaultDisputeGame _game) external {
if (msg.sender != superchainConfig.guardian()) revert Unauthorized();
// Get the metadata of the game.
(GameType gameType, Claim rootClaim, bytes memory extraData) = _game.gameData();
// Grab the verified address of the game based on the game data.
// slither-disable-next-line unused-return
(IDisputeGame factoryRegisteredGame,) =
DISPUTE_GAME_FACTORY.games({ _gameType: gameType, _rootClaim: rootClaim, _extraData: extraData });
// Must be a valid game.
if (address(factoryRegisteredGame) != address(_game)) revert UnregisteredGame();
// The game must have resolved in favor of the root claim.
if (_game.status() != GameStatus.DEFENDER_WINS) revert InvalidGameStatus();
// Update the anchor.
anchors[gameType] =
OutputRoot({ l2BlockNumber: _game.l2BlockNumber(), root: Hash.wrap(_game.rootClaim().raw()) });
}
}
......@@ -2,6 +2,7 @@
pragma solidity 0.8.15;
import { FixedPointMathLib } from "@solady/utils/FixedPointMathLib.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { IDelayedWETH } from "src/dispute/interfaces/IDelayedWETH.sol";
import { IDisputeGame } from "src/dispute/interfaces/IDisputeGame.sol";
......@@ -69,8 +70,8 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
uint256 internal constant HEADER_BLOCK_NUMBER_INDEX = 8;
/// @notice Semantic version.
/// @custom:semver 1.2.0
string public constant version = "1.2.0";
/// @custom:semver 1.3.0
string public constant version = "1.3.0";
/// @notice The starting timestamp of the game
Timestamp public createdAt;
......@@ -136,11 +137,35 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
) {
// The max game depth may not be greater than `LibPosition.MAX_POSITION_BITLEN - 1`.
if (_maxGameDepth > LibPosition.MAX_POSITION_BITLEN - 1) revert MaxDepthTooLarge();
// The split depth cannot be greater than or equal to the max game depth.
if (_splitDepth >= _maxGameDepth) revert InvalidSplitDepth();
// The clock extension may not be greater than the max clock duration.
if (_clockExtension.raw() > _maxClockDuration.raw()) revert InvalidClockExtension();
// The split depth plus one cannot be greater than or equal to the max game depth. We add
// an additional depth to the split depth to avoid a bug in trace ancestor lookup. We know
// that the case where the split depth is the max value for uint256 is equivalent to the
// second check though we do need to check it explicitly to avoid an overflow.
if (_splitDepth == type(uint256).max || _splitDepth + 1 >= _maxGameDepth) revert InvalidSplitDepth();
// The split depth cannot be 0 or 1 to stay in bounds of clock extension arithmetic.
if (_splitDepth < 2) revert InvalidSplitDepth();
// The PreimageOracle challenge period must fit into uint64 so we can safely use it here.
// Runtime check was added instead of changing the ABI since the contract is already
// deployed in production. We perform the same check within the PreimageOracle for the
// benefit of developers but also perform this check here defensively.
if (_vm.oracle().challengePeriod() > type(uint64).max) revert InvalidChallengePeriod();
// Determine the maximum clock extension which is either the split depth extension or the
// maximum game depth extension depending on the configuration of these contracts.
uint256 splitDepthExtension = uint256(_clockExtension.raw()) * 2;
uint256 maxGameDepthExtension = uint256(_clockExtension.raw()) + uint256(_vm.oracle().challengePeriod());
uint256 maxClockExtension = Math.max(splitDepthExtension, maxGameDepthExtension);
// The maximum clock extension must fit into a uint64.
if (maxClockExtension > type(uint64).max) revert InvalidClockExtension();
// The maximum clock extension may not be greater than the maximum clock duration.
if (uint64(maxClockExtension) > _maxClockDuration.raw()) revert InvalidClockExtension();
// Set up initial game state.
GAME_TYPE = _gameType;
ABSOLUTE_PRESTATE = _absolutePrestate;
MAX_GAME_DEPTH = _maxGameDepth;
......@@ -368,17 +393,29 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
// seconds of time.
if (nextDuration.raw() == MAX_CLOCK_DURATION.raw()) revert ClockTimeExceeded();
// If the remaining clock time has less than `CLOCK_EXTENSION` seconds remaining, grant the potential
// grandchild's clock `CLOCK_EXTENSION` seconds. This is to ensure that, even if a player has to inherit another
// team's clock to counter a freeloader claim, they will always have enough time to respond. This extension
// is bounded by the depth of the tree. If the potential grandchild is an execution trace bisection root, the
// clock extension is doubled. This is to allow for extra time for the off-chain challenge agent to generate
// the initial instruction trace on the native FPVM.
if (nextDuration.raw() > MAX_CLOCK_DURATION.raw() - CLOCK_EXTENSION.raw()) {
// If the potential grandchild is an execution trace bisection root, double the clock extension.
uint64 extensionPeriod =
nextPositionDepth == SPLIT_DEPTH - 1 ? CLOCK_EXTENSION.raw() * 2 : CLOCK_EXTENSION.raw();
nextDuration = Duration.wrap(MAX_CLOCK_DURATION.raw() - extensionPeriod);
// Clock extension is a mechanism that automatically extends the clock for a potential
// grandchild claim when there would be less than the clock extension time left if a player
// is forced to inherit another team's clock when countering a freeloader claim. Exact
// amount of clock extension time depends exactly where we are within the game.
uint64 actualExtension;
if (nextPositionDepth == MAX_GAME_DEPTH - 1) {
// If the next position is `MAX_GAME_DEPTH - 1` then we're about to execute a step. Our
// clock extension must therefore account for the LPP challenge period in addition to
// the standard clock extension.
actualExtension = CLOCK_EXTENSION.raw() + uint64(VM.oracle().challengePeriod());
} else if (nextPositionDepth == SPLIT_DEPTH - 1) {
// If the next position is `SPLIT_DEPTH - 1` then we're about to begin an execution
// trace bisection and we need to give extra time for the off-chain challenge agent to
// be able to generate the initial instruction trace on the native FPVM.
actualExtension = CLOCK_EXTENSION.raw() * 2;
} else {
// Otherwise, we just use the standard clock extension.
actualExtension = CLOCK_EXTENSION.raw();
}
// Check if we need to apply the clock extension.
if (nextDuration.raw() > MAX_CLOCK_DURATION.raw() - actualExtension) {
nextDuration = Duration.wrap(MAX_CLOCK_DURATION.raw() - actualExtension);
}
// Construct the next clock with the new duration and the current block timestamp.
......@@ -452,6 +489,9 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
// block number.
uint256 l2Number = startingOutputRoot.l2BlockNumber + disputedPos.traceIndex(SPLIT_DEPTH) + 1;
// Choose the minimum between the `l2BlockNumber` claim and the bisected-to L2 block number.
l2Number = l2Number < l2BlockNumber() ? l2Number : l2BlockNumber();
oracle.loadLocalData(_ident, uuid.raw(), bytes32(l2Number << 0xC0), 8, _partOffset);
} else if (_ident == LocalPreimageKey.CHAIN_ID) {
// Load the chain ID as a big-endian uint64 in the high order 8 bytes of the word.
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IFaultDisputeGame } from "src/dispute/interfaces/IFaultDisputeGame.sol";
import { IDisputeGameFactory } from "src/dispute/interfaces/IDisputeGameFactory.sol";
import "src/dispute/lib/Types.sol";
......@@ -21,4 +22,8 @@ interface IAnchorStateRegistry {
/// the FaultDisputeGame contract and stores it in the registry if the new anchor state is valid and the
/// state is newer than the current anchor state.
function tryUpdateAnchorState() external;
/// @notice Sets the anchor state given the game.
/// @param _game The game to set the anchor state for.
function setAnchorState(IFaultDisputeGame _game) external;
}
......@@ -94,6 +94,9 @@ error InvalidSplitDepth();
/// @notice Thrown on deployment if the max clock duration is less than or equal to the clock extension.
error InvalidClockExtension();
/// @notice Thrown on deployment if the PreimageOracle challenge period is too high.
error InvalidChallengePeriod();
/// @notice Thrown on deployment if the max depth is greater than `LibPosition.`
error MaxDepthTooLarge();
......@@ -123,3 +126,13 @@ error L2BlockNumberChallenged();
/// @notice Thrown when an unauthorized address attempts to interact with the game.
error BadAuth();
////////////////////////////////////////////////////////////////
// `AnchorStateRegistry` Errors //
////////////////////////////////////////////////////////////////
/// @notice Thrown when attempting to set an anchor state using an unregistered game.
error UnregisteredGame();
/// @notice Thrown when attempting to set an anchor state using an invalid game result.
error InvalidGameStatus();
......@@ -21,8 +21,8 @@ import { SuperchainConfig } from "src/L1/SuperchainConfig.sol";
/// Not the prettiest contract in the world, but it gets the job done.
contract DelayedWETH is OwnableUpgradeable, WETH98, IDelayedWETH, ISemver {
/// @notice Semantic version.
/// @custom:semver 1.0.0
string public constant version = "1.0.0";
/// @custom:semver 1.1.0
string public constant version = "1.1.0";
/// @inheritdoc IDelayedWETH
mapping(address => mapping(address => WithdrawalRequest)) public withdrawals;
......@@ -85,7 +85,8 @@ contract DelayedWETH is OwnableUpgradeable, WETH98, IDelayedWETH, ISemver {
function recover(uint256 _wad) external {
require(msg.sender == owner(), "DelayedWETH: not owner");
uint256 amount = _wad < address(this).balance ? _wad : address(this).balance;
payable(msg.sender).transfer(amount);
(bool success,) = payable(msg.sender).call{ value: amount }(hex"");
require(success, "DelayedWETH: recover failed");
}
/// @inheritdoc IDelayedWETH
......
......@@ -7,6 +7,8 @@ import { GnosisSafe as Safe } from "safe-contracts/GnosisSafe.sol";
import "test/safe-tools/SafeTestTools.sol";
import { IDisputeGame } from "src/dispute/interfaces/IDisputeGame.sol";
import { IFaultDisputeGame } from "src/dispute/interfaces/IFaultDisputeGame.sol";
import { AnchorStateRegistry } from "src/dispute/AnchorStateRegistry.sol";
import { DeputyGuardianModule } from "src/Safe/DeputyGuardianModule.sol";
import "src/dispute/lib/Types.sol";
......@@ -148,6 +150,43 @@ contract DeputyGuardianModule_Unpause_TestFail is DeputyGuardianModule_Unpause_T
}
}
contract DeputyGuardianModule_SetAnchorState_TestFail is DeputyGuardianModule_TestInit {
function test_setAnchorState_notDeputyGuardian_reverts() external {
AnchorStateRegistry asr = AnchorStateRegistry(makeAddr("asr"));
vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector));
deputyGuardianModule.setAnchorState(asr, IFaultDisputeGame(address(0)));
}
function test_setAnchorState_targetReverts_reverts() external {
AnchorStateRegistry asr = AnchorStateRegistry(makeAddr("asr"));
vm.mockCallRevert(
address(asr),
abi.encodeWithSelector(asr.setAnchorState.selector),
"AnchorStateRegistry: setAnchorState reverted"
);
vm.prank(address(deputyGuardian));
vm.expectRevert(
abi.encodeWithSelector(ExecutionFailed.selector, "AnchorStateRegistry: setAnchorState reverted")
);
deputyGuardianModule.setAnchorState(asr, IFaultDisputeGame(address(0)));
}
}
contract DeputyGuardianModule_SetAnchorState_Test is DeputyGuardianModule_TestInit {
function test_setAnchorState_succeeds() external {
AnchorStateRegistry asr = AnchorStateRegistry(makeAddr("asr"));
vm.mockCall(
address(asr),
abi.encodeWithSelector(AnchorStateRegistry.setAnchorState.selector, IFaultDisputeGame(address(0))),
""
);
vm.expectEmit(address(safeInstance.safe));
emit ExecutionFromModuleSuccess(address(deputyGuardianModule));
vm.prank(address(deputyGuardian));
deputyGuardianModule.setAnchorState(asr, IFaultDisputeGame(address(0)));
}
}
contract DeputyGuardianModule_BlacklistDisputeGame_Test is DeputyGuardianModule_TestInit {
/// @dev Tests that `blacklistDisputeGame` successfully blacklists a dispute game when called by the deputy
/// guardian.
......
......@@ -617,9 +617,11 @@ contract Specification_Test is CommonTest {
// AnchorStateRegistry
_addSpec({ _name: "AnchorStateRegistry", _sel: _getSel("anchors(uint32)") });
_addSpec({ _name: "AnchorStateRegistry", _sel: _getSel("disputeGameFactory()") });
_addSpec({ _name: "AnchorStateRegistry", _sel: _getSel("initialize((uint32,(bytes32,uint256))[])") });
_addSpec({ _name: "AnchorStateRegistry", _sel: _getSel("initialize((uint32,(bytes32,uint256))[],address)") });
_addSpec({ _name: "AnchorStateRegistry", _sel: _getSel("tryUpdateAnchorState()") });
_addSpec({ _name: "AnchorStateRegistry", _sel: _getSel("setAnchorState(address)"), _auth: Role.GUARDIAN });
_addSpec({ _name: "AnchorStateRegistry", _sel: _getSel("version()") });
_addSpec({ _name: "AnchorStateRegistry", _sel: _getSel("superchainConfig()") });
// PermissionedDisputeGame
_addSpec({ _name: "PermissionedDisputeGame", _sel: _getSel("absolutePrestate()") });
......@@ -826,6 +828,11 @@ contract Specification_Test is CommonTest {
_sel: _getSel("setRespectedGameType(address,uint32)"),
_auth: Role.DEPUTYGUARDIAN
});
_addSpec({
_name: "DeputyGuardianModule",
_sel: _getSel("setAnchorState(address,address)"),
_auth: Role.DEPUTYGUARDIAN
});
_addSpec({ _name: "DeputyGuardianModule", _sel: _getSel("pause()"), _auth: Role.DEPUTYGUARDIAN });
_addSpec({ _name: "DeputyGuardianModule", _sel: _getSel("unpause()"), _auth: Role.DEPUTYGUARDIAN });
_addSpec({ _name: "DeputyGuardianModule", _sel: _getSel("deputyGuardian()") });
......@@ -940,11 +947,12 @@ contract Specification_Test is CommonTest {
/// @notice Ensures that the DeputyGuardian is authorized to take all Guardian actions.
function testDeputyGuardianAuth() public view {
assertEq(specsByRole[Role.DEPUTYGUARDIAN].length, specsByRole[Role.GUARDIAN].length);
assertEq(specsByRole[Role.DEPUTYGUARDIAN].length, 4);
assertEq(specsByRole[Role.DEPUTYGUARDIAN].length, 5);
mapping(bytes4 => Spec) storage dgmFuncSpecs = specs["DeputyGuardianModule"];
mapping(bytes4 => Spec) storage superchainConfigFuncSpecs = specs["SuperchainConfig"];
mapping(bytes4 => Spec) storage portal2FuncSpecs = specs["OptimismPortal2"];
mapping(bytes4 => Spec) storage anchorRegFuncSpecs = specs["AnchorStateRegistry"];
// Ensure that for each of the DeputyGuardianModule's methods there is a corresponding method on another
// system contract authed to the Guardian role.
......@@ -959,5 +967,8 @@ contract Specification_Test is CommonTest {
_assertRolesEq(dgmFuncSpecs[_getSel("setRespectedGameType(address,uint32)")].auth, Role.DEPUTYGUARDIAN);
_assertRolesEq(portal2FuncSpecs[_getSel("setRespectedGameType(uint32)")].auth, Role.GUARDIAN);
_assertRolesEq(dgmFuncSpecs[_getSel("setAnchorState(address,address)")].auth, Role.DEPUTYGUARDIAN);
_assertRolesEq(anchorRegFuncSpecs[_getSel("setAnchorState(address)")].auth, Role.GUARDIAN);
}
}
......@@ -4,6 +4,9 @@ pragma solidity 0.8.15;
import { CommonTest } from "test/setup/CommonTest.sol";
import { MIPS } from "src/cannon/MIPS.sol";
import { PreimageOracle } from "src/cannon/PreimageOracle.sol";
import { MIPSInstructions } from "src/cannon/libraries/MIPSInstructions.sol";
import { MIPSSyscalls as sys } from "src/cannon/libraries/MIPSSyscalls.sol";
import { InvalidExitedValue } from "src/cannon/libraries/CannonErrors.sol";
import "src/dispute/lib/Types.sol";
contract MIPS_Test is CommonTest {
......@@ -58,6 +61,30 @@ contract MIPS_Test is CommonTest {
assertNotEq(postState, bytes32(0));
}
/// @notice Tests that the mips step function fails when the value of the exited field is
/// invalid (anything greater than 1).
/// @param _exited Value to set the exited field to.
function testFuzz_step_invalidExitedValue_fails(uint8 _exited) external {
// Assume
// Make sure the value of _exited is invalid.
_exited = uint8(bound(uint256(_exited), 2, type(uint8).max));
// Rest of this stuff doesn't matter very much, just setting up some state to edit.
// Here just using the parameters for the ADD test below.
uint32 insn = encodespec(17, 18, 8, 0x20);
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
// Compute the encoded state and manipulate it.
bytes memory enc = encodeState(state);
assembly {
mstore8(add(add(enc, 0x20), 89), _exited)
}
// Call the step function and expect a revert.
vm.expectRevert(InvalidExitedValue.selector);
mips.step(enc, proof, 0);
}
function test_add_succeeds() external {
uint32 insn = encodespec(17, 18, 8, 0x20); // add t0, s1, s2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
......@@ -1241,15 +1268,46 @@ contract MIPS_Test is CommonTest {
function test_srav_succeeds() external {
uint32 insn = encodespec(0xa, 0x9, 0x8, 7); // srav t0, t1, t2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0x20_00; // t1
state.registers[10] = 4; // t2
state.registers[9] = 0xdeafbeef; // t1
state.registers[10] = 12; // t2
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = state.registers[9] >> state.registers[10]; // t0
expect.registers[8] = 0xfffdeafb; // t0
expect.registers[9] = state.registers[9];
expect.registers[10] = state.registers[10];
bytes memory enc = encodeState(state);
bytes32 postState = mips.step(enc, proof, 0);
assertEq(postState, outputState(expect), "unexpected post state");
}
/// @notice Tests that the SRAV instruction succeeds when it includes extra bits in the shift
/// amount beyond the lower 5 bits that are actually used for the shift. Extra bits
/// need to be ignored but the instruction should still succeed.
/// @param _rs Value to set in the shift register $rs.
function testFuzz_srav_withExtraBits_succeeds(uint32 _rs) external {
// Assume
// Force _rs to have more than 5 bits set.
_rs = uint32(bound(uint256(_rs), 0x20, type(uint32).max));
uint32 insn = encodespec(0xa, 0x9, 0x8, 7); // srav t0, t1, t2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0xdeadbeef; // t1
state.registers[10] = _rs; // t2
// Calculate shamt
uint32 shamt = state.registers[10] & 0x1F;
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = MIPSInstructions.signExtend(state.registers[9] >> shamt, 32 - shamt); // t0
expect.registers[9] = state.registers[9];
expect.registers[10] = state.registers[10];
......@@ -1426,6 +1484,64 @@ contract MIPS_Test is CommonTest {
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_mmap_succeeds_justWithinMemLimit() external {
uint32 insn = 0x0000000c; // syscall
(bytes32 memRoot, bytes memory proof) = ffi.getCannonMemoryProof(0, insn);
MIPS.State memory state;
state.memRoot = memRoot;
state.nextPC = 4;
state.heap = sys.HEAP_END - 4096; // Set up to increase heap to its limit
state.registers[2] = 4090; // mmap syscall
state.registers[4] = 0x0; // a0
state.registers[5] = 4095; // a1
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
// assert page allocation is aligned to 4k
expect.step = state.step + 1;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.heap = sys.HEAP_END;
expect.registers[2] = state.heap; // Return the old heap value
expect.registers[7] = 0; // No error
expect.registers[4] = state.registers[4]; // a0
expect.registers[5] = state.registers[5]; // a1
bytes32 postState = mips.step(encodedState, proof, 0);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_mmap_fails() external {
uint32 insn = 0x0000000c; // syscall
(bytes32 memRoot, bytes memory proof) = ffi.getCannonMemoryProof(0, insn);
MIPS.State memory state;
state.memRoot = memRoot;
state.nextPC = 4;
state.heap = sys.HEAP_END - 4096; // Set up to increase heap beyond its limit
state.registers[2] = 4090; // mmap syscall
state.registers[4] = 0x0; // a0
state.registers[5] = 4097; // a1
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
// assert page allocation is aligned to 4k
expect.step = state.step + 1;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.heap = state.heap;
expect.registers[2] = sys.SYS_ERROR_SIGNAL; // signal an stdError
expect.registers[7] = sys.EINVAL; // Return error value
expect.registers[4] = state.registers[4]; // a0
expect.registers[5] = state.registers[5]; // a1
bytes32 postState = mips.step(encodedState, proof, 0);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_brk_succeeds() external {
uint32 insn = 0x0000000c; // syscall
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
......
......@@ -20,6 +20,14 @@ contract PreimageOracle_Test is Test {
vm.label(address(oracle), "PreimageOracle");
}
/// @notice Tests that the challenge period cannot be made too large.
/// @param _challengePeriod The challenge period to test.
function testFuzz_constructor_challengePeriodTooLarge_reverts(uint256 _challengePeriod) public {
_challengePeriod = bound(_challengePeriod, uint256(type(uint64).max) + 1, type(uint256).max);
vm.expectRevert("challenge period too large");
new PreimageOracle(0, _challengePeriod);
}
/// @notice Test the pre-image key computation with a known pre-image.
function test_keccak256PreimageKey_succeeds() public pure {
bytes memory preimage = hex"deadbeef";
......@@ -92,8 +100,8 @@ contract PreimageOracle_Test is Test {
{
// Bound the size to [0, 32]
size = bound(size, 0, 32);
// Bound the part offset to [0, size + 8]
partOffset = bound(partOffset, 0, size + 8);
// Bound the part offset to [0, size + 8)
partOffset = bound(partOffset, 0, size + 7);
// Load the local data into the preimage oracle under the test contract's context.
bytes32 contextKey = oracle.loadLocalData(ident, localContext, word, uint8(size), uint8(partOffset));
......@@ -178,8 +186,9 @@ contract PreimageOracle_Test is Test {
bytes memory input = hex"deadbeef";
uint256 offset = 0;
address precompile = address(bytes20(uint160(0x02))); // sha256
bytes32 key = precompilePreimageKey(precompile, input);
oracle.loadPrecompilePreimagePart(offset, precompile, input);
uint64 gas = 72;
bytes32 key = precompilePreimageKey(precompile, gas, input);
oracle.loadPrecompilePreimagePart(offset, precompile, gas, input);
bytes32 part = oracle.preimageParts(key, offset);
// size prefix - 1-byte result + 32-byte sha return data
......@@ -203,8 +212,9 @@ contract PreimageOracle_Test is Test {
bytes memory input = hex"deadbeef";
uint256 offset = 9;
address precompile = address(bytes20(uint160(0x02))); // sha256
bytes32 key = precompilePreimageKey(precompile, input);
oracle.loadPrecompilePreimagePart(offset, precompile, input);
uint64 gas = 72;
bytes32 key = precompilePreimageKey(precompile, gas, input);
oracle.loadPrecompilePreimagePart(offset, precompile, gas, input);
bytes32 part = oracle.preimageParts(key, offset);
// 32-byte sha return data
......@@ -224,8 +234,9 @@ contract PreimageOracle_Test is Test {
bytes memory input = new bytes(193); // invalid input to induce a failed precompile call
uint256 offset = 0;
address precompile = address(bytes20(uint160(0x08))); // bn256Pairing
bytes32 key = precompilePreimageKey(precompile, input);
oracle.loadPrecompilePreimagePart(offset, precompile, input);
uint64 gas = 72;
bytes32 key = precompilePreimageKey(precompile, gas, input);
oracle.loadPrecompilePreimagePart(offset, precompile, gas, input);
bytes32 part = oracle.preimageParts(key, offset);
// size prefix - 1-byte result + 0-byte sha return data
......@@ -249,8 +260,9 @@ contract PreimageOracle_Test is Test {
bytes memory input = hex"deadbeef";
uint256 offset = 41; // 8-byte prefix + 1-byte result + 32-byte sha return data
address precompile = address(bytes20(uint160(0x02))); // sha256
uint64 gas = 72;
vm.expectRevert(PartOffsetOOB.selector);
oracle.loadPrecompilePreimagePart(offset, precompile, input);
oracle.loadPrecompilePreimagePart(offset, precompile, gas, input);
}
/// @notice Tests that a global precompile result cannot be set with an out-of-bounds offset.
......@@ -258,8 +270,34 @@ contract PreimageOracle_Test is Test {
bytes memory input = hex"deadbeef";
uint256 offset = 42;
address precompile = address(bytes20(uint160(0x02))); // sha256
uint64 gas = 72;
vm.expectRevert(PartOffsetOOB.selector);
oracle.loadPrecompilePreimagePart(offset, precompile, input);
oracle.loadPrecompilePreimagePart(offset, precompile, gas, input);
}
/// @notice Tests that a global precompile load succeeds on a variety of gas inputs.
function testFuzz_loadPrecompilePreimagePart_withVaryingGas_succeeds(uint64 _gas) public {
uint64 requiredGas = 100_000;
bytes memory input = hex"deadbeef";
address precompile = address(uint160(0xdeadbeef));
vm.mockCall(precompile, input, hex"abba");
uint256 offset = 0;
uint64 minGas = uint64(bound(_gas, requiredGas * 3, 20_000_000));
vm.expectCallMinGas(precompile, 0, requiredGas, input);
oracle.loadPrecompilePreimagePart{ gas: minGas }(offset, precompile, requiredGas, input);
}
/// @notice Tests that a global precompile load succeeds on insufficient gas.
function test_loadPrecompilePreimagePart_withInsufficientGas_reverts() public {
uint64 requiredGas = 1_000_000;
bytes memory input = hex"deadbeef";
uint256 offset = 0;
address precompile = address(uint160(0xdeadbeef));
// This gas is sufficient to reach the gas checks in `loadPrecompilePreimagePart` but not enough to pass those
// checks
uint64 insufficientGas = requiredGas * 63 / 64;
vm.expectRevert(NotEnoughGas.selector);
oracle.loadPrecompilePreimagePart{ gas: insufficientGas }(offset, precompile, requiredGas, input);
}
}
......@@ -312,6 +350,17 @@ contract PreimageOracle_LargePreimageProposals_Test is Test {
oracle.initLPP{ value: bondSize }(TEST_UUID, 0, uint32(data.length));
}
/// @notice Tests that the `initLPP` function reverts if the proposal has already been initialized.
function test_initLPP_alreadyInitialized_reverts() public {
// Initialize the proposal.
uint256 bondSize = oracle.MIN_BOND_SIZE();
oracle.initLPP{ value: bondSize }(TEST_UUID, 0, uint32(500));
// Re-initialize the proposal.
vm.expectRevert(AlreadyInitialized.selector);
oracle.initLPP{ value: bondSize }(TEST_UUID, 0, uint32(500));
}
/// @notice Gas snapshot for `addLeaves`
function test_addLeaves_gasSnapshot() public {
// Allocate the preimage data.
......@@ -599,6 +648,63 @@ contract PreimageOracle_LargePreimageProposals_Test is Test {
});
}
/// @notice Tests that a proposal cannot be squeezed if the proposal has not been finalized.
function test_squeeze_notFinalized_reverts() public {
// Allocate the preimage data.
bytes memory data = new bytes(136);
for (uint256 i; i < data.length; i++) {
data[i] = 0xFF;
}
// Initialize the proposal.
oracle.initLPP{ value: oracle.MIN_BOND_SIZE() }(TEST_UUID, 0, uint32(data.length));
// Generate the padded input data.
// Since the data is 136 bytes, which is exactly one keccak block, we will add one extra
// keccak block of empty padding to the input data. We need to do this here because the
// addLeavesLPP function will normally perform this padding internally when _finalize is
// set to true but we're explicitly testing the case where _finalize is not true.
bytes memory paddedData = new bytes(136 * 2);
for (uint256 i; i < data.length; i++) {
paddedData[i] = data[i];
}
// Add the leaves to the tree (2 keccak blocks.)
LibKeccak.StateMatrix memory stateMatrix;
bytes32[] memory stateCommitments = _generateStateCommitments(stateMatrix, data);
oracle.addLeavesLPP(TEST_UUID, 0, paddedData, stateCommitments, false);
// Construct the leaf preimage data for the blocks added.
LibKeccak.StateMatrix memory matrix;
PreimageOracle.Leaf[] memory leaves = _generateLeaves(matrix, data);
// Create a proof array with 16 elements.
bytes32[] memory preProof = new bytes32[](16);
preProof[0] = _hashLeaf(leaves[1]);
bytes32[] memory postProof = new bytes32[](16);
postProof[0] = _hashLeaf(leaves[0]);
for (uint256 i = 1; i < preProof.length; i++) {
bytes32 zeroHash = oracle.zeroHashes(i);
preProof[i] = zeroHash;
postProof[i] = zeroHash;
}
// Warp past the challenge period.
vm.warp(block.timestamp + oracle.challengePeriod() + 1 seconds);
// Finalize the proposal.
vm.expectRevert(ActiveProposal.selector);
oracle.squeezeLPP({
_claimant: address(this),
_uuid: TEST_UUID,
_stateMatrix: _stateMatrixAtBlockIndex(data, 1),
_preState: leaves[0],
_preStateProof: preProof,
_postState: leaves[1],
_postStateProof: postProof
});
}
/// @notice Tests that a proposal cannot be finalized until it has passed the challenge period.
function test_squeeze_challengePeriodActive_reverts() public {
// Allocate the preimage data.
......@@ -754,7 +860,7 @@ contract PreimageOracle_LargePreimageProposals_Test is Test {
/// @notice Tests that squeezing a large preimage proposal after the challenge period has passed always succeeds and
/// persists the correct data.
function testFuzz_squeeze_succeeds(uint256 _numBlocks, uint32 _partOffset) public {
function testFuzz_squeezeLPP_succeeds(uint256 _numBlocks, uint32 _partOffset) public {
_numBlocks = bound(_numBlocks, 1, 2 ** 8);
_partOffset = uint32(bound(_partOffset, 0, _numBlocks * LibKeccak.BLOCK_SIZE_BYTES + 8 - 1));
......@@ -1363,9 +1469,9 @@ function _setStatusByte(bytes32 _hash, uint8 _status) pure returns (bytes32 out_
}
/// @notice Computes a precompile key for a given precompile address and input.
function precompilePreimageKey(address _precompile, bytes memory _input) pure returns (bytes32 key_) {
bytes memory p = abi.encodePacked(_precompile, _input);
uint256 sz = 20 + _input.length;
function precompilePreimageKey(address _precompile, uint64 _gas, bytes memory _input) pure returns (bytes32 key_) {
bytes memory p = abi.encodePacked(_precompile, _gas, _input);
uint256 sz = 20 + 8 + _input.length;
assembly {
let h := keccak256(add(0x20, p), sz)
// Mask out prefix byte, replace with type 6 byte
......
......@@ -5,7 +5,7 @@ import "src/dispute/lib/Types.sol";
import "src/dispute/lib/Errors.sol";
import { Test } from "forge-std/Test.sol";
import { FaultDisputeGame_Init, _changeClaimStatus } from "test/dispute/FaultDisputeGame.t.sol";
import { FaultDisputeGame_Init, IDisputeGame, _changeClaimStatus } from "test/dispute/FaultDisputeGame.t.sol";
contract AnchorStateRegistry_Init is FaultDisputeGame_Init {
function setUp() public virtual override {
......@@ -124,7 +124,7 @@ contract AnchorStateRegistry_TryUpdateAnchorState_Test is AnchorStateRegistry_In
// Try to update the anchor state.
vm.prank(address(gameProxy));
vm.expectRevert("AnchorStateRegistry: fault dispute game not registered with factory");
vm.expectRevert(UnregisteredGame.selector);
anchorStateRegistry.tryUpdateAnchorState();
// Confirm that the anchor state has not updated.
......@@ -132,4 +132,88 @@ contract AnchorStateRegistry_TryUpdateAnchorState_Test is AnchorStateRegistry_In
assertEq(updatedL2BlockNumber, l2BlockNumber);
assertEq(updatedRoot.raw(), root.raw());
}
function test_setAnchorState_invalidGame_fails() public {
// Confirm that the anchor state is older than the game state.
(Hash root, uint256 l2BlockNumber) = anchorStateRegistry.anchors(gameProxy.gameType());
require(l2BlockNumber < gameProxy.l2BlockNumber(), "l2BlockNumber < gameProxy.l2BlockNumber()");
// Mock the state that we want.
vm.mockCall(
address(disputeGameFactory),
abi.encodeWithSelector(
disputeGameFactory.games.selector, gameProxy.gameType(), gameProxy.rootClaim(), gameProxy.extraData()
),
abi.encode(address(0), 0)
);
// Try to update the anchor state.
vm.prank(superchainConfig.guardian());
vm.expectRevert(UnregisteredGame.selector);
anchorStateRegistry.setAnchorState(gameProxy);
// Confirm that the anchor state has not updated.
(Hash updatedRoot, uint256 updatedL2BlockNumber) = anchorStateRegistry.anchors(gameProxy.gameType());
assertEq(updatedL2BlockNumber, l2BlockNumber);
assertEq(updatedRoot.raw(), root.raw());
}
/// @dev Tests that setting the anchor state fails if the challenger wins.
function test_setAnchorState_challengerWins_fails() public {
(Hash root, uint256 l2BlockNumber) = anchorStateRegistry.anchors(gameProxy.gameType());
// Mock the state that we want.
vm.mockCall(
address(gameProxy),
abi.encodeWithSelector(gameProxy.status.selector),
abi.encode(GameStatus.CHALLENGER_WINS)
);
// Set the anchor state.
vm.prank(superchainConfig.guardian());
vm.expectRevert(InvalidGameStatus.selector);
anchorStateRegistry.setAnchorState(gameProxy);
// Confirm that the anchor state has not updated.
(Hash updatedRoot, uint256 updatedL2BlockNumber) = anchorStateRegistry.anchors(gameProxy.gameType());
assertEq(updatedL2BlockNumber, l2BlockNumber);
assertEq(updatedRoot.raw(), root.raw());
}
/// @dev Tests that setting the anchor state fails if the game is in progress.
function test_setAnchorState_gameInProgress_fails() public {
(Hash root, uint256 l2BlockNumber) = anchorStateRegistry.anchors(gameProxy.gameType());
// Mock the state that we want.
vm.mockCall(
address(gameProxy), abi.encodeWithSelector(gameProxy.status.selector), abi.encode(GameStatus.IN_PROGRESS)
);
// Set the anchor state.
vm.prank(superchainConfig.guardian());
vm.expectRevert(InvalidGameStatus.selector);
anchorStateRegistry.setAnchorState(gameProxy);
// Confirm that the anchor state has not updated.
(Hash updatedRoot, uint256 updatedL2BlockNumber) = anchorStateRegistry.anchors(gameProxy.gameType());
assertEq(updatedL2BlockNumber, l2BlockNumber);
assertEq(updatedRoot.raw(), root.raw());
}
/// @dev Tests that setting the anchor state succeeds.
function test_setAnchorState_succeeds() public {
// Mock the state that we want.
vm.mockCall(
address(gameProxy), abi.encodeWithSelector(gameProxy.status.selector), abi.encode(GameStatus.DEFENDER_WINS)
);
// Set the anchor state.
vm.prank(superchainConfig.guardian());
anchorStateRegistry.setAnchorState(gameProxy);
// Confirm that the anchor state has updated.
(Hash updatedRoot, uint256 updatedL2BlockNumber) = anchorStateRegistry.anchors(gameProxy.gameType());
assertEq(updatedL2BlockNumber, gameProxy.l2BlockNumber());
assertEq(updatedRoot.raw(), gameProxy.rootClaim().raw());
}
}
......@@ -9,6 +9,7 @@ import { DisputeGameFactory, IDisputeGameFactory } from "src/dispute/DisputeGame
import { IDisputeGame } from "src/dispute/interfaces/IDisputeGame.sol";
import { DelayedWETH } from "src/dispute/weth/DelayedWETH.sol";
import { Proxy } from "src/universal/Proxy.sol";
import { Burn } from "src/libraries/Burn.sol";
import { CommonTest } from "test/setup/CommonTest.sol";
contract DelayedWETH_Init is CommonTest {
......@@ -45,7 +46,7 @@ contract DelayedWETH_Unlock_Test is DelayedWETH_Init {
assertEq(timestamp, block.timestamp);
}
/// @dev TEsts that unlocking twice is successful and timestamp/amount is updated.
/// @dev Tests that unlocking twice is successful and timestamp/amount is updated.
function test_unlock_twice_succeeds() public {
// Unlock once.
uint256 ts = block.timestamp;
......@@ -170,24 +171,35 @@ contract DelayedWETH_Withdraw_Test is DelayedWETH_Init {
}
contract DelayedWETH_Recover_Test is DelayedWETH_Init {
/// @dev Tests that recovering WETH succeeds.
function test_recover_succeeds() public {
/// @dev Tests that recovering WETH succeeds. Makes sure that doing so succeeds with any amount
/// of ETH in the contract and any amount of gas used in the fallback function up to a
/// maximum of 20,000,000 gas. Owner contract should never be using that much gas but we
/// might as well set a very large upper bound for ourselves.
/// @param _amount Amount of WETH to recover.
/// @param _fallbackGasUsage Amount of gas to use in the fallback function.
function testFuzz_recover_succeeds(uint256 _amount, uint256 _fallbackGasUsage) public {
// Assume
_fallbackGasUsage = bound(_fallbackGasUsage, 0, 20000000);
// Set up the gas burner.
FallbackGasUser gasUser = new FallbackGasUser(_fallbackGasUsage);
// Transfer ownership to alice.
delayedWeth.transferOwnership(alice);
delayedWeth.transferOwnership(address(gasUser));
// Give the contract some WETH to recover.
vm.deal(address(delayedWeth), 1 ether);
vm.deal(address(delayedWeth), _amount);
// Record the initial balance.
uint256 initialBalance = address(alice).balance;
uint256 initialBalance = address(gasUser).balance;
// Recover the WETH.
vm.prank(alice);
delayedWeth.recover(1 ether);
vm.prank(address(gasUser));
delayedWeth.recover(_amount);
// Verify the WETH was recovered.
assertEq(address(delayedWeth).balance, 0);
assertEq(address(alice).balance, initialBalance + 1 ether);
assertEq(address(gasUser).balance, initialBalance + _amount);
}
/// @dev Tests that recovering WETH by non-owner fails.
......@@ -219,6 +231,23 @@ contract DelayedWETH_Recover_Test is DelayedWETH_Init {
assertEq(address(delayedWeth).balance, 0);
assertEq(address(alice).balance, initialBalance + 0.5 ether);
}
/// @dev Tests that recover reverts when recipient reverts.
function test_recover_whenRecipientReverts_fails() public {
// Set up the reverter.
FallbackReverter reverter = new FallbackReverter();
// Transfer ownership to the reverter.
delayedWeth.transferOwnership(address(reverter));
// Give the contract some WETH to recover.
vm.deal(address(delayedWeth), 1 ether);
// Recover fails.
vm.expectRevert("DelayedWETH: recover failed");
vm.prank(address(reverter));
delayedWeth.recover(1 ether);
}
}
contract DelayedWETH_Hold_Test is DelayedWETH_Init {
......@@ -255,3 +284,39 @@ contract DelayedWETH_Hold_Test is DelayedWETH_Init {
delayedWeth.hold(bob, 1 ether);
}
}
/// @title FallbackGasUser
/// @notice Contract that burns gas in the fallback function.
contract FallbackGasUser {
/// @notice Amount of gas to use in the fallback function.
uint256 public gas;
/// @param _gas Amount of gas to use in the fallback function.
constructor(uint256 _gas) {
gas = _gas;
}
/// @notice Burn gas on fallback;
fallback() external payable {
Burn.gas(gas);
}
/// @notice Burn gas on receive.
receive() external payable {
Burn.gas(gas);
}
}
/// @title FallbackReverter
/// @notice Contract that reverts in the fallback function.
contract FallbackReverter {
/// @notice Revert on fallback.
fallback() external payable {
revert("FallbackReverter: revert");
}
/// @notice Revert on receive.
receive() external payable {
revert("FallbackReverter: revert");
}
}
......@@ -45,7 +45,10 @@ contract FaultDisputeGame_Init is DisputeGameFactory_Init {
// Set the extra data for the game creation
extraData = abi.encode(l2BlockNumber);
AlphabetVM _vm = new AlphabetVM(absolutePrestate, new PreimageOracle(0, 0));
// Set preimage oracle challenge period to something arbitrary (4 seconds) just so we can
// actually test the clock extensions later on. This is not a realistic value.
PreimageOracle oracle = new PreimageOracle(0, 4);
AlphabetVM _vm = new AlphabetVM(absolutePrestate, oracle);
// Deploy an implementation of the fault game
gameImpl = new FaultDisputeGame({
......@@ -128,12 +131,66 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
});
}
/// @dev Tests that the constructor of the `FaultDisputeGame` reverts when the challenge period
// of the preimage oracle being used by the game's VM is too large.
/// @param _challengePeriod The challenge period of the preimage oracle.
function testFuzz_constructor_oracleChallengePeriodTooLarge_reverts(uint256 _challengePeriod) public {
_challengePeriod = bound(_challengePeriod, uint256(type(uint64).max) + 1, type(uint256).max);
PreimageOracle oracle = new PreimageOracle(0, 0);
AlphabetVM alphabetVM = new AlphabetVM(absolutePrestate, oracle);
// PreimageOracle constructor will revert if the challenge period is too large, so we need
// to mock the call to pretend this is a bugged implementation where the challenge period
// is allowed to be too large.
vm.mockCall(
address(oracle), abi.encodeWithSelector(oracle.challengePeriod.selector), abi.encode(_challengePeriod)
);
vm.expectRevert(InvalidChallengePeriod.selector);
new FaultDisputeGame({
_gameType: GAME_TYPE,
_absolutePrestate: absolutePrestate,
_maxGameDepth: 2 ** 3,
_splitDepth: 2 ** 2,
_clockExtension: Duration.wrap(3 hours),
_maxClockDuration: Duration.wrap(3.5 days),
_vm: alphabetVM,
_weth: DelayedWETH(payable(address(0))),
_anchorStateRegistry: IAnchorStateRegistry(address(0)),
_l2ChainId: 10
});
}
/// @dev Tests that the constructor of the `FaultDisputeGame` reverts when the `_splitDepth`
/// parameter is greater than or equal to the `MAX_GAME_DEPTH`
function testFuzz_constructor_invalidSplitDepth_reverts(uint256 _splitDepth) public {
AlphabetVM alphabetVM = new AlphabetVM(absolutePrestate, new PreimageOracle(0, 0));
_splitDepth = bound(_splitDepth, 2 ** 3, type(uint256).max);
uint256 maxGameDepth = 2 ** 3;
_splitDepth = bound(_splitDepth, maxGameDepth - 1, type(uint256).max);
vm.expectRevert(InvalidSplitDepth.selector);
new FaultDisputeGame({
_gameType: GAME_TYPE,
_absolutePrestate: absolutePrestate,
_maxGameDepth: maxGameDepth,
_splitDepth: _splitDepth,
_clockExtension: Duration.wrap(3 hours),
_maxClockDuration: Duration.wrap(3.5 days),
_vm: alphabetVM,
_weth: DelayedWETH(payable(address(0))),
_anchorStateRegistry: IAnchorStateRegistry(address(0)),
_l2ChainId: 10
});
}
/// @dev Tests that the constructor of the `FaultDisputeGame` reverts when the `_splitDepth`
/// parameter is less than the minimum split depth (currently 2).
function testFuzz_constructor_lowSplitDepth_reverts(uint256 _splitDepth) public {
AlphabetVM alphabetVM = new AlphabetVM(absolutePrestate, new PreimageOracle(0, 0));
uint256 minSplitDepth = 2;
_splitDepth = bound(_splitDepth, 0, minSplitDepth - 1);
vm.expectRevert(InvalidSplitDepth.selector);
new FaultDisputeGame({
_gameType: GAME_TYPE,
......@@ -149,8 +206,8 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
});
}
/// @dev Tests that the constructor of the `FaultDisputeGame` reverts when clock extension is greater than the
/// max clock duration.
/// @dev Tests that the constructor of the `FaultDisputeGame` reverts when clock extension * 2 is greater than
/// the max clock duration.
function testFuzz_constructor_clockExtensionTooLong_reverts(
uint64 _maxClockDuration,
uint64 _clockExtension
......@@ -159,8 +216,11 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
{
AlphabetVM alphabetVM = new AlphabetVM(absolutePrestate, new PreimageOracle(0, 0));
_maxClockDuration = uint64(bound(_maxClockDuration, 0, type(uint64).max - 1));
_clockExtension = uint64(bound(_clockExtension, _maxClockDuration + 1, type(uint64).max));
// Force the clock extension * 2 to be greater than the max clock duration, but keep things within
// bounds of the uint64 type.
_maxClockDuration = uint64(bound(_maxClockDuration, 0, type(uint64).max / 2 - 1));
_clockExtension = uint64(bound(_clockExtension, _maxClockDuration / 2 + 1, type(uint64).max / 2));
vm.expectRevert(InvalidClockExtension.selector);
new FaultDisputeGame({
_gameType: GAME_TYPE,
......@@ -456,47 +516,126 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
assertEq(clock.raw(), LibClock.wrap(Duration.wrap(20), Timestamp.wrap(uint64(block.timestamp))).raw());
}
/// @notice Static unit test that checks proper clock extension.
function test_move_clockExtensionCorrectness_succeeds() public {
/// @dev Tests that the standard clock extension is triggered for a move that is not the
/// split depth or the max game depth.
function test_move_standardClockExtension_succeeds() public {
(,,,,,, Clock clock) = gameProxy.claimData(0);
assertEq(clock.raw(), LibClock.wrap(Duration.wrap(0), Timestamp.wrap(uint64(block.timestamp))).raw());
uint256 bond;
Claim disputed;
Claim claim = _dummyClaim();
uint256 splitDepth = gameProxy.splitDepth();
uint64 halfGameDuration = gameProxy.maxClockDuration().raw();
uint64 clockExtension = gameProxy.clockExtension().raw();
// Make an initial attack against the root claim with 1 second left on the clock. The grandchild should be
// allocated exactly `clockExtension` seconds remaining on their potential clock.
vm.warp(block.timestamp + halfGameDuration - 1 seconds);
uint256 bond = _getRequiredBond(0);
(,,,, Claim disputed,,) = gameProxy.claimData(0);
// Warp ahead so that the next move will trigger a clock extension. We warp to the very
// first timestamp where a clock extension should be triggered.
vm.warp(block.timestamp + halfGameDuration - clockExtension + 1 seconds);
// Execute a move that should cause a clock extension.
bond = _getRequiredBond(0);
(,,,, disputed,,) = gameProxy.claimData(0);
gameProxy.attack{ value: bond }(disputed, 0, claim);
(,,,,,, clock) = gameProxy.claimData(1);
// The clock should have been pushed back to the clock extension time.
assertEq(clock.duration().raw(), halfGameDuration - clockExtension);
// Warp ahead to the last second of the root claim defender's clock, and bisect all the way down to the move
// above the `SPLIT_DEPTH`. This warp guarantees that all moves from here on out will have clock extensions.
vm.warp(block.timestamp + halfGameDuration - 1 seconds);
// Warp ahead again so that clock extensions will also trigger for the other team. Here we
// only warp to the clockExtension time because we'll be warping ahead by one second during
// each additional move.
vm.warp(block.timestamp + halfGameDuration - clockExtension);
// Work our way down to the split depth.
for (uint256 i = 1; i < splitDepth - 2; i++) {
// Warp ahead by one second so that the next move will trigger a clock extension.
vm.warp(block.timestamp + 1 seconds);
// Execute a move that should cause a clock extension.
bond = _getRequiredBond(i);
(,,,, disputed,,) = gameProxy.claimData(i);
gameProxy.attack{ value: bond }(disputed, i, claim);
(,,,,,, clock) = gameProxy.claimData(i + 1);
// The clock should have been pushed back to the clock extension time.
assertEq(clock.duration().raw(), halfGameDuration - clockExtension);
}
}
// Warp ahead 1 seconds to have `clockExtension - 1 seconds` left on the next move's clock.
vm.warp(block.timestamp + 1 seconds);
function test_move_splitDepthClockExtension_succeeds() public {
(,,,,,, Clock clock) = gameProxy.claimData(0);
assertEq(clock.raw(), LibClock.wrap(Duration.wrap(0), Timestamp.wrap(uint64(block.timestamp))).raw());
uint256 bond;
Claim disputed;
Claim claim = _dummyClaim();
uint256 splitDepth = gameProxy.splitDepth();
uint64 halfGameDuration = gameProxy.maxClockDuration().raw();
uint64 clockExtension = gameProxy.clockExtension().raw();
// The move above the split depth's grand child is the execution trace bisection root. The grandchild should
// be allocated `clockExtension * 2` seconds on their potential clock, if currently they have less than
// `clockExtension` seconds left.
// Work our way down to the split depth without moving ahead in time, we don't care about
// the exact clock here, just don't want take the clock below the clock extension time that
// we're trying to test here.
for (uint256 i = 0; i < splitDepth - 2; i++) {
bond = _getRequiredBond(i);
(,,,, disputed,,) = gameProxy.claimData(i);
gameProxy.attack{ value: bond }(disputed, i, claim);
}
// Warp ahead to the very first timestamp where a clock extension should be triggered.
vm.warp(block.timestamp + halfGameDuration - clockExtension * 2 + 1 seconds);
// Execute a move that should cause a clock extension.
bond = _getRequiredBond(splitDepth - 2);
(,,,, disputed,,) = gameProxy.claimData(splitDepth - 2);
gameProxy.attack{ value: bond }(disputed, splitDepth - 2, claim);
(,,,,,, clock) = gameProxy.claimData(splitDepth - 1);
// The clock should have been pushed back to the clock extension time.
assertEq(clock.duration().raw(), halfGameDuration - clockExtension * 2);
}
function test_move_maxGameDepthClockExtension_succeeds() public {
(,,,,,, Clock clock) = gameProxy.claimData(0);
assertEq(clock.raw(), LibClock.wrap(Duration.wrap(0), Timestamp.wrap(uint64(block.timestamp))).raw());
uint256 bond;
Claim disputed;
Claim claim = _dummyClaim();
uint256 splitDepth = gameProxy.splitDepth();
uint64 halfGameDuration = gameProxy.maxClockDuration().raw();
uint64 clockExtension = gameProxy.clockExtension().raw();
// Work our way down to the split depth without moving ahead in time, we don't care about
// the exact clock here, just don't want take the clock below the clock extension time that
// we're trying to test here.
for (uint256 i = 0; i < gameProxy.maxGameDepth() - 2; i++) {
bond = _getRequiredBond(i);
(,,,, disputed,,) = gameProxy.claimData(i);
gameProxy.attack{ value: bond }(disputed, i, claim);
// Change the claim status when we're crossing the split depth.
if (i == splitDepth - 2) {
claim = _changeClaimStatus(claim, VMStatuses.PANIC);
}
}
// Warp ahead to the very first timestamp where a clock extension should be triggered.
vm.warp(block.timestamp + halfGameDuration - (clockExtension + gameProxy.vm().oracle().challengePeriod()) + 1);
// Execute a move that should cause a clock extension.
bond = _getRequiredBond(gameProxy.maxGameDepth() - 2);
(,,,, disputed,,) = gameProxy.claimData(gameProxy.maxGameDepth() - 2);
gameProxy.attack{ value: bond }(disputed, gameProxy.maxGameDepth() - 2, claim);
(,,,,,, clock) = gameProxy.claimData(gameProxy.maxGameDepth() - 1);
// The clock should have been pushed back to the clock extension time.
assertEq(
clock.duration().raw(), halfGameDuration - (clockExtension + gameProxy.vm().oracle().challengePeriod())
);
}
/// @dev Tests that an identical claim cannot be made twice. The duplicate claim attempt should
/// revert with the `ClaimAlreadyExists` error.
function test_move_duplicateClaim_reverts() public {
......@@ -1685,6 +1824,70 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
}
}
/// @dev Tests that the L2 block number claim is favored over the bisected-to block when adding data
///
function test_addLocalData_l2BlockNumberExtension_succeeds() public {
// Deploy a new dispute game with a L2 block number claim of 8. This is directly in the middle of
// the leaves in our output bisection test tree, at SPLIT_DEPTH = 2 ** 2
FaultDisputeGame game = FaultDisputeGame(
address(disputeGameFactory.create(GAME_TYPE, Claim.wrap(bytes32(uint256(0xFF))), abi.encode(uint256(8))))
);
// Get a claim below the split depth so that we can add local data for an execution trace subgame.
{
Claim disputed;
Position parent;
Position pos;
for (uint256 i; i < 4; i++) {
(,,,,, parent,) = game.claimData(i);
pos = parent.move(true);
uint256 bond = game.getRequiredBond(pos);
(,,,, disputed,,) = game.claimData(i);
if (i == 0) {
game.attack{ value: bond }(disputed, i, Claim.wrap(bytes32(i)));
} else {
game.defend{ value: bond }(disputed, i, Claim.wrap(bytes32(i)));
}
}
(,,,,, parent,) = game.claimData(4);
pos = parent.move(true);
uint256 lastBond = game.getRequiredBond(pos);
(,,,, disputed,,) = game.claimData(4);
game.defend{ value: lastBond }(disputed, 4, _changeClaimStatus(ROOT_CLAIM, VMStatuses.INVALID));
}
// Expected start/disputed claims
bytes32 startingClaim = bytes32(uint256(3));
Position startingPos = LibPosition.wrap(4, 14);
bytes32 disputedClaim = bytes32(uint256(0xFF));
Position disputedPos = LibPosition.wrap(0, 0);
// Expected local data. This should be `l2BlockNumber`, and not the actual bisected-to block,
// as we choose the minimum between the two.
bytes32 expectedNumber = bytes32(uint256(8 << 0xC0));
uint256 expectedLen = 8;
uint256 l2NumberIdent = LocalPreimageKey.DISPUTED_L2_BLOCK_NUMBER;
// Compute the preimage key for the local data
bytes32 localContext = keccak256(abi.encode(startingClaim, startingPos, disputedClaim, disputedPos));
bytes32 rawKey = keccak256(abi.encode(l2NumberIdent | (1 << 248), address(game), localContext));
bytes32 key = bytes32((uint256(rawKey) & ~uint256(0xFF << 248)) | (1 << 248));
IPreimageOracle oracle = IPreimageOracle(address(game.vm().oracle()));
game.addLocalData(l2NumberIdent, 5, 0);
(bytes32 dat, uint256 datLen) = oracle.readPreimage(key, 0);
assertEq(dat >> 0xC0, bytes32(expectedLen));
assertEq(datLen, expectedLen + 8);
game.addLocalData(l2NumberIdent, 5, 8);
(dat, datLen) = oracle.readPreimage(key, 8);
assertEq(dat, expectedNumber);
assertEq(datLen, expectedLen);
}
/// @dev Static unit test asserting that resolveClaim isn't possible if there's time
/// left for a counter.
function test_resolution_lastSecondDisputes_succeeds() public {
......
......@@ -13,9 +13,9 @@ contract DeploymentSummary is DeploymentSummaryCode {
Vm private constant vm = Vm(VM_ADDRESS);
address internal constant addressManagerAddress = 0x50EEf481cae4250d252Ae577A09bF514f224C6C4;
address internal constant anchorStateRegistryAddress = 0xE2a80256d1dAFe06683F231F8e9561639Aa0e9b9;
address internal constant anchorStateRegistryProxyAddress = 0xd6EAF4c146261653EE059077B78ED088Add54309;
address internal constant delayedWETHAddress = 0x49BBFf1629824A1e7993Ab5c17AFa45D24AB28c9;
address internal constant anchorStateRegistryAddress = 0x2d0983b9B70A282D344520a78CC3009bd0656aB4;
address internal constant anchorStateRegistryProxyAddress = 0x970670459734a83899773A0fd45941B5afC1200e;
address internal constant delayedWETHAddress = 0x07F69b19532476c6Cd03056D6BC3F1b110Ab7538;
address internal constant delayedWETHProxyAddress = 0xEF179756ea6525AFade217cA5aB0b1b5CfE0fd92;
address internal constant disputeGameFactoryAddress = 0x20B168142354Cee65a32f6D8cf3033E592299765;
address internal constant disputeGameFactoryProxyAddress = 0x5207CfA0166E8de0FCdFd78B4d17b68587bE306d;
......@@ -27,13 +27,14 @@ contract DeploymentSummary is DeploymentSummaryCode {
address internal constant l1StandardBridgeProxyAddress = 0x20A42a5a785622c6Ba2576B2D6e924aA82BFA11D;
address internal constant l2OutputOracleAddress = 0x19652082F846171168Daf378C4fD3ee85a0D4A60;
address internal constant l2OutputOracleProxyAddress = 0x39Af23E00F1e662025aA01b0cEdA19542B78DF99;
address internal constant mipsAddress = 0xB3A0348310a0ff78E5FbDB7f14BB7d3e02d40773;
address internal constant mipsAddress = 0xaB5b145Bd477C9Bf42F3Ee3f0d988Abef3a27679;
address internal constant optimismMintableERC20FactoryAddress = 0x39Aea2Dd53f2d01c15877aCc2791af6BDD7aD567;
address internal constant optimismMintableERC20FactoryProxyAddress = 0xc7B87b2b892EA5C3CfF47168881FE168C00377FB;
address internal constant optimismPortalAddress = 0xbdD90485FCbcac869D5b5752179815a3103d8131;
address internal constant optimismPortal2Address = 0xae5DadFc48928543f706a9E6Ce25c682aaD2b63b;
address internal constant optimismPortalProxyAddress = 0x1c23A6d89F95ef3148BCDA8E242cAb145bf9c0E4;
address internal constant preimageOracleAddress = 0x3bd7E801E51d48c5d94Ea68e8B801DFFC275De75;
address internal constant permissionedDelayedWETHProxyAddress = 0xd6EAF4c146261653EE059077B78ED088Add54309;
address internal constant preimageOracleAddress = 0x5A996D7C1b5De7C21121F06D99ADFa088d4b779e;
address internal constant protocolVersionsAddress = 0xfbfD64a6C0257F613feFCe050Aa30ecC3E3d7C3F;
address internal constant protocolVersionsProxyAddress = 0x4C52a6277b1B84121b3072C0c92b6Be0b7CC10F1;
address internal constant proxyAdminAddress = 0x62c20Aa1e0272312BC100b4e23B4DC1Ed96dD7D1;
......@@ -44,8 +45,8 @@ contract DeploymentSummary is DeploymentSummaryCode {
address internal constant systemConfigAddress = 0x67866A5052E5302aaD08e9f352331fd8622eB6DC;
address internal constant systemConfigProxyAddress = 0x0c8b5822b6e02CDa722174F19A1439A7495a3fA6;
address internal constant systemOwnerSafeAddress = 0x7C0c8a15773ED7B50E7c738D1aF4c5e3a2b210BD;
address internal constant acc32Address = 0x357A483a8923686E7fA454Ee93bbc11aFB114743;
address internal constant acc33Address = 0xb6b1579AA54e2F61e621a40d5F2704D717B3544F;
address internal constant acc34Address = 0x59B99034FBdd5E554661a2100cB2b6b7C5d495F8;
function recreateDeployment() public {
bytes32 slot;
......@@ -200,6 +201,10 @@ contract DeploymentSummary is DeploymentSummaryCode {
slot = hex"b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103";
value = hex"00000000000000000000000062c20aa1e0272312bc100b4e23b4dc1ed96dd7d1";
vm.store(delayedWETHProxyAddress, slot, value);
vm.etch(permissionedDelayedWETHProxyAddress, permissionedDelayedWETHProxyCode);
slot = hex"b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103";
value = hex"00000000000000000000000062c20aa1e0272312bc100b4e23b4dc1ed96dd7d1";
vm.store(permissionedDelayedWETHProxyAddress, slot, value);
vm.etch(anchorStateRegistryProxyAddress, anchorStateRegistryProxyCode);
slot = hex"b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103";
value = hex"00000000000000000000000062c20aa1e0272312bc100b4e23b4dc1ed96dd7d1";
......@@ -419,13 +424,7 @@ contract DeploymentSummary is DeploymentSummaryCode {
vm.etch(mipsAddress, mipsCode);
vm.etch(anchorStateRegistryAddress, anchorStateRegistryCode);
slot = hex"0000000000000000000000000000000000000000000000000000000000000000";
value = hex"0000000000000000000000000000000000000000000000000000000000000001";
vm.store(anchorStateRegistryAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000000";
value = hex"0000000000000000000000000000000000000000000000000000000000000101";
vm.store(anchorStateRegistryAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000000";
value = hex"0000000000000000000000000000000000000000000000000000000000000001";
value = hex"00000000000000000000000000000000000000000000000000000000000000ff";
vm.store(anchorStateRegistryAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000005";
value = hex"0000000000000000000000000000000000000000000000000000000000000003";
......@@ -698,7 +697,7 @@ contract DeploymentSummary is DeploymentSummaryCode {
value = hex"000000000000000000000000000000000000000000000000000000000000000e";
vm.store(systemOwnerSafeAddress, slot, value);
slot = hex"360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
value = hex"00000000000000000000000049bbff1629824a1e7993ab5c17afa45d24ab28c9";
value = hex"00000000000000000000000007f69b19532476c6cd03056d6bc3f1b110ab7538";
vm.store(delayedWETHProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000000";
value = hex"0000000000000000000000000000000000000000000000000000000000000001";
......@@ -722,7 +721,31 @@ contract DeploymentSummary is DeploymentSummaryCode {
value = hex"000000000000000000000000000000000000000000000000000000000000000f";
vm.store(systemOwnerSafeAddress, slot, value);
slot = hex"360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
value = hex"000000000000000000000000e2a80256d1dafe06683f231f8e9561639aa0e9b9";
value = hex"00000000000000000000000007f69b19532476c6cd03056d6bc3f1b110ab7538";
vm.store(permissionedDelayedWETHProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000000";
value = hex"0000000000000000000000000000000000000000000000000000000000000001";
vm.store(permissionedDelayedWETHProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000000";
value = hex"0000000000000000000000000000000000000000000000000000000000000101";
vm.store(permissionedDelayedWETHProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000033";
value = hex"00000000000000000000000062c20aa1e0272312bc100b4e23b4dc1ed96dd7d1";
vm.store(permissionedDelayedWETHProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000033";
value = hex"0000000000000000000000001804c8ab1f12e6bbf3894d4083f33e07309d1f38";
vm.store(permissionedDelayedWETHProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000068";
value = hex"0000000000000000000000004f559f30f5eb88d635fde1548c4267db8fab0351";
vm.store(permissionedDelayedWETHProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000000";
value = hex"0000000000000000000000000000000000000000000000000000000000000001";
vm.store(permissionedDelayedWETHProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000005";
value = hex"0000000000000000000000000000000000000000000000000000000000000010";
vm.store(systemOwnerSafeAddress, slot, value);
slot = hex"360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
value = hex"0000000000000000000000002d0983b9b70a282d344520a78cc3009bd0656ab4";
vm.store(anchorStateRegistryProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000000";
value = hex"0000000000000000000000000000000000000000000000000000000000000001";
......@@ -745,16 +768,19 @@ contract DeploymentSummary is DeploymentSummaryCode {
slot = hex"1d32deecea32fd1365d10df47fc6666a05871102e61a115a5c569bca7e5de14d";
value = hex"deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
vm.store(anchorStateRegistryProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000002";
value = hex"0000000000000000000000004f559f30f5eb88d635fde1548c4267db8fab0351";
vm.store(anchorStateRegistryProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000000";
value = hex"0000000000000000000000000000000000000000000000000000000000000001";
vm.store(anchorStateRegistryProxyAddress, slot, value);
vm.etch(acc32Address, acc32Code);
vm.etch(acc33Address, acc33Code);
slot = hex"ffdfc1249c027f9191656349feb0761381bb32c9f557e01f419fd08754bf5a1b";
value = hex"000000000000000000000000357a483a8923686e7fa454ee93bbc11afb114743";
value = hex"000000000000000000000000b6b1579aa54e2f61e621a40d5f2704d717b3544f";
vm.store(disputeGameFactoryProxyAddress, slot, value);
vm.etch(acc33Address, acc33Code);
vm.etch(acc34Address, acc34Code);
slot = hex"4d5a9bd2e41301728d41c8e705190becb4e74abe869f75bdb405b63716a35f9e";
value = hex"000000000000000000000000b6b1579aa54e2f61e621a40d5f2704d717b3544f";
value = hex"00000000000000000000000059b99034fbdd5e554661a2100cb2b6b7c5d495f8";
vm.store(disputeGameFactoryProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000033";
value = hex"0000000000000000000000007c0c8a15773ed7b50e7c738d1af4c5e3a2b210bd";
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -13,9 +13,9 @@ contract DeploymentSummaryFaultProofs is DeploymentSummaryFaultProofsCode {
Vm private constant vm = Vm(VM_ADDRESS);
address internal constant addressManagerAddress = 0x50EEf481cae4250d252Ae577A09bF514f224C6C4;
address internal constant anchorStateRegistryAddress = 0xE2a80256d1dAFe06683F231F8e9561639Aa0e9b9;
address internal constant anchorStateRegistryProxyAddress = 0xd6EAF4c146261653EE059077B78ED088Add54309;
address internal constant delayedWETHAddress = 0x49BBFf1629824A1e7993Ab5c17AFa45D24AB28c9;
address internal constant anchorStateRegistryAddress = 0x2d0983b9B70A282D344520a78CC3009bd0656aB4;
address internal constant anchorStateRegistryProxyAddress = 0x970670459734a83899773A0fd45941B5afC1200e;
address internal constant delayedWETHAddress = 0x07F69b19532476c6Cd03056D6BC3F1b110Ab7538;
address internal constant delayedWETHProxyAddress = 0xEF179756ea6525AFade217cA5aB0b1b5CfE0fd92;
address internal constant disputeGameFactoryAddress = 0x20B168142354Cee65a32f6D8cf3033E592299765;
address internal constant disputeGameFactoryProxyAddress = 0x5207CfA0166E8de0FCdFd78B4d17b68587bE306d;
......@@ -27,13 +27,14 @@ contract DeploymentSummaryFaultProofs is DeploymentSummaryFaultProofsCode {
address internal constant l1StandardBridgeProxyAddress = 0x20A42a5a785622c6Ba2576B2D6e924aA82BFA11D;
address internal constant l2OutputOracleAddress = 0x19652082F846171168Daf378C4fD3ee85a0D4A60;
address internal constant l2OutputOracleProxyAddress = 0x39Af23E00F1e662025aA01b0cEdA19542B78DF99;
address internal constant mipsAddress = 0xB3A0348310a0ff78E5FbDB7f14BB7d3e02d40773;
address internal constant mipsAddress = 0xaB5b145Bd477C9Bf42F3Ee3f0d988Abef3a27679;
address internal constant optimismMintableERC20FactoryAddress = 0x39Aea2Dd53f2d01c15877aCc2791af6BDD7aD567;
address internal constant optimismMintableERC20FactoryProxyAddress = 0xc7B87b2b892EA5C3CfF47168881FE168C00377FB;
address internal constant optimismPortalAddress = 0xbdD90485FCbcac869D5b5752179815a3103d8131;
address internal constant optimismPortal2Address = 0xae5DadFc48928543f706a9E6Ce25c682aaD2b63b;
address internal constant optimismPortalProxyAddress = 0x1c23A6d89F95ef3148BCDA8E242cAb145bf9c0E4;
address internal constant preimageOracleAddress = 0x3bd7E801E51d48c5d94Ea68e8B801DFFC275De75;
address internal constant permissionedDelayedWETHProxyAddress = 0xd6EAF4c146261653EE059077B78ED088Add54309;
address internal constant preimageOracleAddress = 0x5A996D7C1b5De7C21121F06D99ADFa088d4b779e;
address internal constant protocolVersionsAddress = 0xfbfD64a6C0257F613feFCe050Aa30ecC3E3d7C3F;
address internal constant protocolVersionsProxyAddress = 0x4C52a6277b1B84121b3072C0c92b6Be0b7CC10F1;
address internal constant proxyAdminAddress = 0x62c20Aa1e0272312BC100b4e23B4DC1Ed96dD7D1;
......@@ -44,8 +45,8 @@ contract DeploymentSummaryFaultProofs is DeploymentSummaryFaultProofsCode {
address internal constant systemConfigAddress = 0x67866A5052E5302aaD08e9f352331fd8622eB6DC;
address internal constant systemConfigProxyAddress = 0x0c8b5822b6e02CDa722174F19A1439A7495a3fA6;
address internal constant systemOwnerSafeAddress = 0x7C0c8a15773ED7B50E7c738D1aF4c5e3a2b210BD;
address internal constant acc32Address = 0x357A483a8923686E7fA454Ee93bbc11aFB114743;
address internal constant acc33Address = 0xb6b1579AA54e2F61e621a40d5F2704D717B3544F;
address internal constant acc34Address = 0x59B99034FBdd5E554661a2100cB2b6b7C5d495F8;
function recreateDeployment() public {
bytes32 slot;
......@@ -200,6 +201,10 @@ contract DeploymentSummaryFaultProofs is DeploymentSummaryFaultProofsCode {
slot = hex"b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103";
value = hex"00000000000000000000000062c20aa1e0272312bc100b4e23b4dc1ed96dd7d1";
vm.store(delayedWETHProxyAddress, slot, value);
vm.etch(permissionedDelayedWETHProxyAddress, permissionedDelayedWETHProxyCode);
slot = hex"b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103";
value = hex"00000000000000000000000062c20aa1e0272312bc100b4e23b4dc1ed96dd7d1";
vm.store(permissionedDelayedWETHProxyAddress, slot, value);
vm.etch(anchorStateRegistryProxyAddress, anchorStateRegistryProxyCode);
slot = hex"b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103";
value = hex"00000000000000000000000062c20aa1e0272312bc100b4e23b4dc1ed96dd7d1";
......@@ -419,13 +424,7 @@ contract DeploymentSummaryFaultProofs is DeploymentSummaryFaultProofsCode {
vm.etch(mipsAddress, mipsCode);
vm.etch(anchorStateRegistryAddress, anchorStateRegistryCode);
slot = hex"0000000000000000000000000000000000000000000000000000000000000000";
value = hex"0000000000000000000000000000000000000000000000000000000000000001";
vm.store(anchorStateRegistryAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000000";
value = hex"0000000000000000000000000000000000000000000000000000000000000101";
vm.store(anchorStateRegistryAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000000";
value = hex"0000000000000000000000000000000000000000000000000000000000000001";
value = hex"00000000000000000000000000000000000000000000000000000000000000ff";
vm.store(anchorStateRegistryAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000005";
value = hex"0000000000000000000000000000000000000000000000000000000000000003";
......@@ -701,7 +700,7 @@ contract DeploymentSummaryFaultProofs is DeploymentSummaryFaultProofsCode {
value = hex"000000000000000000000000000000000000000000000000000000000000000e";
vm.store(systemOwnerSafeAddress, slot, value);
slot = hex"360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
value = hex"00000000000000000000000049bbff1629824a1e7993ab5c17afa45d24ab28c9";
value = hex"00000000000000000000000007f69b19532476c6cd03056d6bc3f1b110ab7538";
vm.store(delayedWETHProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000000";
value = hex"0000000000000000000000000000000000000000000000000000000000000001";
......@@ -725,7 +724,31 @@ contract DeploymentSummaryFaultProofs is DeploymentSummaryFaultProofsCode {
value = hex"000000000000000000000000000000000000000000000000000000000000000f";
vm.store(systemOwnerSafeAddress, slot, value);
slot = hex"360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
value = hex"000000000000000000000000e2a80256d1dafe06683f231f8e9561639aa0e9b9";
value = hex"00000000000000000000000007f69b19532476c6cd03056d6bc3f1b110ab7538";
vm.store(permissionedDelayedWETHProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000000";
value = hex"0000000000000000000000000000000000000000000000000000000000000001";
vm.store(permissionedDelayedWETHProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000000";
value = hex"0000000000000000000000000000000000000000000000000000000000000101";
vm.store(permissionedDelayedWETHProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000033";
value = hex"00000000000000000000000062c20aa1e0272312bc100b4e23b4dc1ed96dd7d1";
vm.store(permissionedDelayedWETHProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000033";
value = hex"0000000000000000000000001804c8ab1f12e6bbf3894d4083f33e07309d1f38";
vm.store(permissionedDelayedWETHProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000068";
value = hex"0000000000000000000000004f559f30f5eb88d635fde1548c4267db8fab0351";
vm.store(permissionedDelayedWETHProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000000";
value = hex"0000000000000000000000000000000000000000000000000000000000000001";
vm.store(permissionedDelayedWETHProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000005";
value = hex"0000000000000000000000000000000000000000000000000000000000000010";
vm.store(systemOwnerSafeAddress, slot, value);
slot = hex"360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
value = hex"0000000000000000000000002d0983b9b70a282d344520a78cc3009bd0656ab4";
vm.store(anchorStateRegistryProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000000";
value = hex"0000000000000000000000000000000000000000000000000000000000000001";
......@@ -748,16 +771,19 @@ contract DeploymentSummaryFaultProofs is DeploymentSummaryFaultProofsCode {
slot = hex"1d32deecea32fd1365d10df47fc6666a05871102e61a115a5c569bca7e5de14d";
value = hex"deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
vm.store(anchorStateRegistryProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000002";
value = hex"0000000000000000000000004f559f30f5eb88d635fde1548c4267db8fab0351";
vm.store(anchorStateRegistryProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000000";
value = hex"0000000000000000000000000000000000000000000000000000000000000001";
vm.store(anchorStateRegistryProxyAddress, slot, value);
vm.etch(acc32Address, acc32Code);
vm.etch(acc33Address, acc33Code);
slot = hex"ffdfc1249c027f9191656349feb0761381bb32c9f557e01f419fd08754bf5a1b";
value = hex"000000000000000000000000357a483a8923686e7fa454ee93bbc11afb114743";
value = hex"000000000000000000000000b6b1579aa54e2f61e621a40d5f2704d717b3544f";
vm.store(disputeGameFactoryProxyAddress, slot, value);
vm.etch(acc33Address, acc33Code);
vm.etch(acc34Address, acc34Code);
slot = hex"4d5a9bd2e41301728d41c8e705190becb4e74abe869f75bdb405b63716a35f9e";
value = hex"000000000000000000000000b6b1579aa54e2f61e621a40d5f2704d717b3544f";
value = hex"00000000000000000000000059b99034fbdd5e554661a2100cb2b6b7c5d495f8";
vm.store(disputeGameFactoryProxyAddress, slot, value);
slot = hex"0000000000000000000000000000000000000000000000000000000000000033";
value = hex"0000000000000000000000007c0c8a15773ed7b50e7c738d1af4c5e3a2b210bd";
......
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