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

Merge branch 'develop' into ctb/create2-deploy

parents 2df86f34 bc602c07
---
'@eth-optimism/chain-mon': minor
---
Use node.js v18
......@@ -26,7 +26,7 @@ jobs:
steps:
- name: Check out source code
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
# This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
fetch-depth: 0
......@@ -51,7 +51,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
......@@ -78,7 +78,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
......@@ -105,7 +105,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
......@@ -132,7 +132,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
......@@ -159,7 +159,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
......@@ -186,7 +186,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
......@@ -223,7 +223,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
......
......@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
......
......@@ -32,7 +32,7 @@ jobs:
id-token: write
steps:
- name: Checkout Repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
# This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
fetch-depth: 0
......@@ -76,7 +76,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
......@@ -113,7 +113,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
......@@ -140,7 +140,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
......@@ -167,7 +167,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
......@@ -194,7 +194,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
......@@ -221,7 +221,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
......@@ -248,7 +248,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
......
......@@ -40,7 +40,7 @@ jobs:
environment: op-stack-production
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Fetch tags
run: git fetch --tags origin --force
- name: Setup Python 3.10
......
......@@ -5,7 +5,7 @@ go 1.20
require github.com/ethereum-optimism/optimism v0.0.0
require (
golang.org/x/crypto v0.12.0 // indirect
golang.org/x/crypto v0.13.0 // indirect
golang.org/x/sys v0.12.0 // indirect
)
......
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
......@@ -9,7 +9,11 @@ finalized and may change without notice.
### Contents
* Overview
* Specifications
* [Generic Fault Proof System](../../specs/fault-proof.md)
* [Generic Dispute Game Interface](../../specs/dispute-game-interface.md)
* [Fault Dispute Game](../../specs/fault-dispute-game.md)
* [Cannon VM](../../specs/cannon-fault-proof-vm.md)
* [Deployment Details](./deployments.md)
* [Manual Usage](./manual.md)
* [Creating Traces with Cannon](./cannon.md)
......
......@@ -38,7 +38,7 @@ require (
github.com/prometheus/client_golang v1.14.0
github.com/stretchr/testify v1.8.4
github.com/urfave/cli/v2 v2.25.7
golang.org/x/crypto v0.12.0
golang.org/x/crypto v0.13.0
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df
golang.org/x/sync v0.3.0
golang.org/x/term v0.12.0
......@@ -196,7 +196,7 @@ require (
golang.org/x/mod v0.11.0 // indirect
golang.org/x/net v0.12.0 // indirect
golang.org/x/sys v0.12.0 // indirect
golang.org/x/text v0.12.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/tools v0.9.3 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
......
......@@ -886,8 +886,8 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME=
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
......@@ -1023,8 +1023,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
......
......@@ -78,5 +78,6 @@
"dependsOn": ["^build", "build:contracts"],
"outputs": ["{projectRoot}/dist"]
}
}
},
"$schema": "./node_modules/nx/schemas/nx-schema.json"
}
......@@ -3,7 +3,7 @@
The `op-challenger` is a modular **op-stack** challenge agent
written in golang for dispute games including, but not limited to, attestation games, fault
games, and validity games. To learn more about dispute games, visit the
[dispute game specs](../specs/dispute-game.md).
[fault proof specs](../specs/fault-proof.md).
## Quickstart
......
......@@ -17,8 +17,7 @@ import (
type Responder interface {
CallResolve(ctx context.Context) (gameTypes.GameStatus, error)
Resolve(ctx context.Context) error
Respond(ctx context.Context, response types.Claim) error
Step(ctx context.Context, stepData types.StepCallData) error
PerformAction(ctx context.Context, action solver.Action) error
}
type ClaimLoader interface {
......@@ -27,7 +26,7 @@ type ClaimLoader interface {
type Agent struct {
metrics metrics.Metricer
solver *solver.Solver
solver *solver.GameSolver
loader ClaimLoader
responder Responder
updater types.OracleUpdater
......@@ -39,7 +38,7 @@ type Agent struct {
func NewAgent(m metrics.Metricer, loader ClaimLoader, maxDepth int, trace types.TraceProvider, responder Responder, updater types.OracleUpdater, agreeWithProposedOutput bool, log log.Logger) *Agent {
return &Agent{
metrics: m,
solver: solver.NewSolver(maxDepth, trace),
solver: solver.NewGameSolver(maxDepth, trace),
loader: loader,
responder: responder,
updater: updater,
......@@ -58,16 +57,34 @@ func (a *Agent) Act(ctx context.Context) error {
if err != nil {
return fmt.Errorf("create game from contracts: %w", err)
}
// Create counter claims
for _, claim := range game.Claims() {
if err := a.move(ctx, claim, game); err != nil && !errors.Is(err, types.ErrGameDepthReached) {
log.Error("Failed to move", "err", err)
// Calculate the actions to take
actions, err := a.solver.CalculateNextActions(ctx, game)
if err != nil {
log.Error("Failed to calculate all required moves", "err", err)
}
// Perform the actions
for _, action := range actions {
log := a.log.New("action", action.Type, "is_attack", action.IsAttack, "parent", action.ParentIdx, "value", action.Value)
if action.OracleData != nil {
a.log.Info("Updating oracle data", "oracleKey", action.OracleData.OracleKey, "oracleData", action.OracleData.OracleData)
if err := a.updater.UpdateOracle(ctx, action.OracleData); err != nil {
return fmt.Errorf("failed to load oracle data: %w", err)
}
}
switch action.Type {
case solver.ActionTypeMove:
a.metrics.RecordGameMove()
case solver.ActionTypeStep:
a.metrics.RecordGameStep()
}
// Step on all leaf claims
for _, claim := range game.Claims() {
if err := a.step(ctx, claim, game); err != nil {
log.Error("Failed to step", "err", err)
log.Info("Performing action")
err := a.responder.PerformAction(ctx, action)
if err != nil {
log.Error("Action failed", "err", err)
}
}
return nil
......@@ -118,68 +135,3 @@ func (a *Agent) newGameFromContracts(ctx context.Context) (types.Game, error) {
}
return game, nil
}
// move determines & executes the next move given a claim
func (a *Agent) move(ctx context.Context, claim types.Claim, game types.Game) error {
nextMove, err := a.solver.NextMove(ctx, claim, game.AgreeWithClaimLevel(claim))
if err != nil {
return fmt.Errorf("execute next move: %w", err)
}
if nextMove == nil {
a.log.Debug("No next move")
return nil
}
move := *nextMove
log := a.log.New("is_defend", move.DefendsParent(), "depth", move.Depth(), "index_at_depth", move.IndexAtDepth(),
"value", move.Value, "trace_index", move.TraceIndex(a.maxDepth),
"parent_value", claim.Value, "parent_trace_index", claim.TraceIndex(a.maxDepth))
if game.IsDuplicate(move) {
log.Debug("Skipping duplicate move")
return nil
}
a.metrics.RecordGameMove()
log.Info("Performing move")
return a.responder.Respond(ctx, move)
}
// step determines & executes the next step against a leaf claim through the responder
func (a *Agent) step(ctx context.Context, claim types.Claim, game types.Game) error {
if claim.Depth() != a.maxDepth {
return nil
}
agreeWithClaimLevel := game.AgreeWithClaimLevel(claim)
if agreeWithClaimLevel {
a.log.Debug("Agree with leaf claim, skipping step", "claim_depth", claim.Depth(), "maxDepth", a.maxDepth)
return nil
}
if claim.Countered {
a.log.Debug("Step already executed against claim", "depth", claim.Depth(), "index_at_depth", claim.IndexAtDepth(), "value", claim.Value)
return nil
}
a.log.Info("Attempting step", "claim_depth", claim.Depth(), "maxDepth", a.maxDepth)
step, err := a.solver.AttemptStep(ctx, claim, agreeWithClaimLevel)
if err != nil {
return fmt.Errorf("attempt step: %w", err)
}
if step.OracleData != nil {
a.log.Info("Updating oracle data", "oracleKey", step.OracleData.OracleKey, "oracleData", step.OracleData.OracleData)
if err := a.updater.UpdateOracle(ctx, step.OracleData); err != nil {
return fmt.Errorf("failed to load oracle data: %w", err)
}
}
a.log.Info("Performing step", "is_attack", step.IsAttack,
"depth", step.LeafClaim.Depth(), "index_at_depth", step.LeafClaim.IndexAtDepth(), "value", step.LeafClaim.Value)
a.metrics.RecordGameStep()
callData := types.StepCallData{
ClaimIndex: uint64(step.LeafClaim.ContractIndex),
IsAttack: step.IsAttack,
StateData: step.PreState,
Proof: step.ProofData,
}
return a.responder.Step(ctx, callData)
}
......@@ -5,6 +5,7 @@ import (
"errors"
"testing"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/solver"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/test"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/alphabet"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
......@@ -144,11 +145,7 @@ func (s *stubResponder) Resolve(ctx context.Context) error {
return s.resolveErr
}
func (s *stubResponder) Respond(ctx context.Context, response types.Claim) error {
panic("Not implemented")
}
func (s *stubResponder) Step(ctx context.Context, stepData types.StepCallData) error {
func (s *stubResponder) PerformAction(ctx context.Context, response solver.Action) error {
panic("Not implemented")
}
......
......@@ -5,7 +5,6 @@ import (
"testing"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
"github.com/ethereum/go-ethereum/common"
......@@ -94,12 +93,7 @@ func TestBuildFaultStepData(t *testing.T) {
resp, _ := newTestFaultResponder(t)
data, err := resp.buildStepTxData(types.StepCallData{
ClaimIndex: 2,
IsAttack: false,
StateData: []byte{0x01},
Proof: []byte{0x02},
})
data, err := resp.buildStepTxData(2, false, []byte{0x01}, []byte{0x02})
require.NoError(t, err)
opts.GasLimit = 100_000
......
......@@ -5,7 +5,7 @@ import (
"math/big"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/solver"
gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
......@@ -16,8 +16,8 @@ import (
"github.com/ethereum/go-ethereum/log"
)
// faultResponder implements the [Responder] interface to send onchain transactions.
type faultResponder struct {
// FaultResponder implements the [Responder] interface to send onchain transactions.
type FaultResponder struct {
log log.Logger
txMgr txmgr.TxManager
......@@ -26,13 +26,13 @@ type faultResponder struct {
fdgAbi *abi.ABI
}
// NewFaultResponder returns a new [faultResponder].
func NewFaultResponder(logger log.Logger, txManagr txmgr.TxManager, fdgAddr common.Address) (*faultResponder, error) {
// NewFaultResponder returns a new [FaultResponder].
func NewFaultResponder(logger log.Logger, txManagr txmgr.TxManager, fdgAddr common.Address) (*FaultResponder, error) {
fdgAbi, err := bindings.FaultDisputeGameMetaData.GetAbi()
if err != nil {
return nil, err
}
return &faultResponder{
return &FaultResponder{
log: logger,
txMgr: txManagr,
fdgAddr: fdgAddr,
......@@ -41,7 +41,7 @@ func NewFaultResponder(logger log.Logger, txManagr txmgr.TxManager, fdgAddr comm
}
// buildFaultDefendData creates the transaction data for the Defend function.
func (r *faultResponder) buildFaultDefendData(parentContractIndex int, pivot [32]byte) ([]byte, error) {
func (r *FaultResponder) buildFaultDefendData(parentContractIndex int, pivot [32]byte) ([]byte, error) {
return r.fdgAbi.Pack(
"defend",
big.NewInt(int64(parentContractIndex)),
......@@ -50,7 +50,7 @@ func (r *faultResponder) buildFaultDefendData(parentContractIndex int, pivot [32
}
// buildFaultAttackData creates the transaction data for the Attack function.
func (r *faultResponder) buildFaultAttackData(parentContractIndex int, pivot [32]byte) ([]byte, error) {
func (r *FaultResponder) buildFaultAttackData(parentContractIndex int, pivot [32]byte) ([]byte, error) {
return r.fdgAbi.Pack(
"attack",
big.NewInt(int64(parentContractIndex)),
......@@ -59,30 +59,13 @@ func (r *faultResponder) buildFaultAttackData(parentContractIndex int, pivot [32
}
// buildResolveData creates the transaction data for the Resolve function.
func (r *faultResponder) buildResolveData() ([]byte, error) {
func (r *FaultResponder) buildResolveData() ([]byte, error) {
return r.fdgAbi.Pack("resolve")
}
// BuildTx builds the transaction for the [faultResponder].
func (r *faultResponder) BuildTx(ctx context.Context, response types.Claim) ([]byte, error) {
if response.DefendsParent() {
txData, err := r.buildFaultDefendData(response.ParentContractIndex, response.ValueBytes())
if err != nil {
return nil, err
}
return txData, nil
} else {
txData, err := r.buildFaultAttackData(response.ParentContractIndex, response.ValueBytes())
if err != nil {
return nil, err
}
return txData, nil
}
}
// CallResolve determines if the resolve function on the fault dispute game contract
// would succeed. Returns the game status if the call would succeed, errors otherwise.
func (r *faultResponder) CallResolve(ctx context.Context) (gameTypes.GameStatus, error) {
func (r *FaultResponder) CallResolve(ctx context.Context) (gameTypes.GameStatus, error) {
txData, err := r.buildResolveData()
if err != nil {
return gameTypes.GameStatusInProgress, err
......@@ -102,7 +85,7 @@ func (r *faultResponder) CallResolve(ctx context.Context) (gameTypes.GameStatus,
}
// Resolve executes a resolve transaction to resolve a fault dispute game.
func (r *faultResponder) Resolve(ctx context.Context) error {
func (r *FaultResponder) Resolve(ctx context.Context) error {
txData, err := r.buildResolveData()
if err != nil {
return err
......@@ -111,9 +94,19 @@ func (r *faultResponder) Resolve(ctx context.Context) error {
return r.sendTxAndWait(ctx, txData)
}
// Respond takes a [Claim] and executes the response action.
func (r *faultResponder) Respond(ctx context.Context, response types.Claim) error {
txData, err := r.BuildTx(ctx, response)
func (r *FaultResponder) PerformAction(ctx context.Context, action solver.Action) error {
var txData []byte
var err error
switch action.Type {
case solver.ActionTypeMove:
if action.IsAttack {
txData, err = r.buildFaultAttackData(action.ParentIdx, action.Value)
} else {
txData, err = r.buildFaultDefendData(action.ParentIdx, action.Value)
}
case solver.ActionTypeStep:
txData, err = r.buildStepTxData(uint64(action.ParentIdx), action.IsAttack, action.PreState, action.ProofData)
}
if err != nil {
return err
}
......@@ -122,7 +115,7 @@ func (r *faultResponder) Respond(ctx context.Context, response types.Claim) erro
// sendTxAndWait sends a transaction through the [txmgr] and waits for a receipt.
// This sets the tx GasLimit to 0, performing gas estimation online through the [txmgr].
func (r *faultResponder) sendTxAndWait(ctx context.Context, txData []byte) error {
func (r *FaultResponder) sendTxAndWait(ctx context.Context, txData []byte) error {
receipt, err := r.txMgr.Send(ctx, txmgr.TxCandidate{
To: &r.fdgAddr,
TxData: txData,
......@@ -140,21 +133,12 @@ func (r *faultResponder) sendTxAndWait(ctx context.Context, txData []byte) error
}
// buildStepTxData creates the transaction data for the step function.
func (r *faultResponder) buildStepTxData(stepData types.StepCallData) ([]byte, error) {
func (r *FaultResponder) buildStepTxData(claimIdx uint64, isAttack bool, stateData []byte, proof []byte) ([]byte, error) {
return r.fdgAbi.Pack(
"step",
big.NewInt(int64(stepData.ClaimIndex)),
stepData.IsAttack,
stepData.StateData,
stepData.Proof,
big.NewInt(int64(claimIdx)),
isAttack,
stateData,
proof,
)
}
// Step accepts step data and executes the step on the fault dispute game contract.
func (r *faultResponder) Step(ctx context.Context, stepData types.StepCallData) error {
txData, err := r.buildStepTxData(stepData)
if err != nil {
return err
}
return r.sendTxAndWait(ctx, txData)
}
......@@ -7,7 +7,7 @@ import (
"testing"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/solver"
gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types"
"github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
......@@ -74,73 +74,98 @@ func TestResolve(t *testing.T) {
}
// TestRespond tests the [Responder.Respond] method.
func TestRespond(t *testing.T) {
func TestPerformAction(t *testing.T) {
t.Run("send fails", func(t *testing.T) {
responder, mockTxMgr := newTestFaultResponder(t)
mockTxMgr.sendFails = true
err := responder.Respond(context.Background(), generateMockResponseClaim())
err := responder.PerformAction(context.Background(), solver.Action{
Type: solver.ActionTypeMove,
ParentIdx: 123,
IsAttack: true,
Value: common.Hash{0xaa},
})
require.ErrorIs(t, err, mockSendError)
require.Equal(t, 0, mockTxMgr.sends)
})
t.Run("sends response", func(t *testing.T) {
responder, mockTxMgr := newTestFaultResponder(t)
err := responder.Respond(context.Background(), generateMockResponseClaim())
err := responder.PerformAction(context.Background(), solver.Action{
Type: solver.ActionTypeMove,
ParentIdx: 123,
IsAttack: true,
Value: common.Hash{0xaa},
})
require.NoError(t, err)
require.Equal(t, 1, mockTxMgr.sends)
})
}
// TestBuildTx tests the [Responder.BuildTx] method.
func TestBuildTx(t *testing.T) {
t.Run("attack", func(t *testing.T) {
responder, _ := newTestFaultResponder(t)
responseClaim := generateMockResponseClaim()
responseClaim.ParentContractIndex = 7
tx, err := responder.BuildTx(context.Background(), responseClaim)
responder, mockTxMgr := newTestFaultResponder(t)
action := solver.Action{
Type: solver.ActionTypeMove,
ParentIdx: 123,
IsAttack: true,
Value: common.Hash{0xaa},
}
err := responder.PerformAction(context.Background(), action)
require.NoError(t, err)
// Pack the tx data manually.
fdgAbi, err := bindings.FaultDisputeGameMetaData.GetAbi()
require.NoError(t, err)
parent := big.NewInt(int64(7))
claim := responseClaim.ValueBytes()
expected, err := fdgAbi.Pack("attack", parent, claim)
expected, err := fdgAbi.Pack("attack", big.NewInt(int64(action.ParentIdx)), action.Value)
require.NoError(t, err)
require.Equal(t, expected, tx)
require.Len(t, mockTxMgr.sent, 1)
require.Equal(t, expected, mockTxMgr.sent[0].TxData)
})
t.Run("defend", func(t *testing.T) {
responder, _ := newTestFaultResponder(t)
responseClaim := types.Claim{
ClaimData: types.ClaimData{
Value: common.Hash{0x01},
Position: types.NewPositionFromGIndex(3),
},
Parent: types.ClaimData{
Value: common.Hash{0x02},
Position: types.NewPositionFromGIndex(6),
},
ContractIndex: 0,
ParentContractIndex: 7,
responder, mockTxMgr := newTestFaultResponder(t)
action := solver.Action{
Type: solver.ActionTypeMove,
ParentIdx: 123,
IsAttack: false,
Value: common.Hash{0xaa},
}
tx, err := responder.BuildTx(context.Background(), responseClaim)
err := responder.PerformAction(context.Background(), action)
require.NoError(t, err)
// Pack the tx data manually.
fdgAbi, err := bindings.FaultDisputeGameMetaData.GetAbi()
require.NoError(t, err)
parent := big.NewInt(int64(7))
claim := responseClaim.ValueBytes()
expected, err := fdgAbi.Pack("defend", parent, claim)
expected, err := fdgAbi.Pack("defend", big.NewInt(int64(action.ParentIdx)), action.Value)
require.NoError(t, err)
require.Len(t, mockTxMgr.sent, 1)
require.Equal(t, expected, mockTxMgr.sent[0].TxData)
})
t.Run("step", func(t *testing.T) {
responder, mockTxMgr := newTestFaultResponder(t)
action := solver.Action{
Type: solver.ActionTypeStep,
ParentIdx: 123,
IsAttack: true,
PreState: []byte{1, 2, 3},
ProofData: []byte{4, 5, 6},
}
err := responder.PerformAction(context.Background(), action)
require.NoError(t, err)
// Pack the tx data manually.
fdgAbi, err := bindings.FaultDisputeGameMetaData.GetAbi()
require.NoError(t, err)
require.Equal(t, expected, tx)
expected, err := fdgAbi.Pack("step", big.NewInt(int64(action.ParentIdx)), true, action.PreState, action.ProofData)
require.NoError(t, err)
require.Len(t, mockTxMgr.sent, 1)
require.Equal(t, expected, mockTxMgr.sent[0].TxData)
})
}
func newTestFaultResponder(t *testing.T) (*faultResponder, *mockTxManager) {
func newTestFaultResponder(t *testing.T) (*FaultResponder, *mockTxManager) {
log := testlog.Logger(t, log.LvlError)
mockTxMgr := &mockTxManager{}
responder, err := NewFaultResponder(log, mockTxMgr, mockFdgAddress)
......@@ -151,6 +176,7 @@ func newTestFaultResponder(t *testing.T) (*faultResponder, *mockTxManager) {
type mockTxManager struct {
from common.Address
sends int
sent []txmgr.TxCandidate
calls int
sendFails bool
callFails bool
......@@ -162,6 +188,7 @@ func (m *mockTxManager) Send(ctx context.Context, candidate txmgr.TxCandidate) (
return nil, mockSendError
}
m.sends++
m.sent = append(m.sent, candidate)
return ethtypes.NewReceipt(
[]byte{},
false,
......@@ -189,18 +216,3 @@ func (m *mockTxManager) BlockNumber(ctx context.Context) (uint64, error) {
func (m *mockTxManager) From() common.Address {
return m.from
}
func generateMockResponseClaim() types.Claim {
return types.Claim{
ClaimData: types.ClaimData{
Value: common.Hash{0x01},
Position: types.NewPositionFromGIndex(2),
},
Parent: types.ClaimData{
Value: common.Hash{0x02},
Position: types.NewPositionFromGIndex(1),
},
ContractIndex: 0,
ParentContractIndex: 0,
}
}
package solver
import (
"context"
"errors"
"fmt"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum/go-ethereum/common"
)
type ActionType string
const (
ActionTypeMove ActionType = "move"
ActionTypeStep ActionType = "step"
)
func (a ActionType) String() string {
return string(a)
}
type Action struct {
Type ActionType
ParentIdx int
IsAttack bool
// Moves
Value common.Hash
// Steps
PreState []byte
ProofData []byte
OracleData *types.PreimageOracleData
}
type GameSolver struct {
claimSolver *claimSolver
gameDepth int
}
func NewGameSolver(gameDepth int, trace types.TraceProvider) *GameSolver {
return &GameSolver{
claimSolver: newClaimSolver(gameDepth, trace),
gameDepth: gameDepth,
}
}
func (s *GameSolver) CalculateNextActions(ctx context.Context, game types.Game) ([]Action, error) {
var errs []error
var actions []Action
for _, claim := range game.Claims() {
var action *Action
var err error
if claim.Depth() == s.gameDepth {
action, err = s.calculateStep(ctx, game, claim)
} else {
action, err = s.calculateMove(ctx, game, claim)
}
if err != nil {
errs = append(errs, err)
continue
}
if action == nil {
continue
}
actions = append(actions, *action)
}
return actions, errors.Join(errs...)
}
func (s *GameSolver) calculateStep(ctx context.Context, game types.Game, claim types.Claim) (*Action, error) {
if claim.Countered {
return nil, nil
}
if game.AgreeWithClaimLevel(claim) {
return nil, nil
}
step, err := s.claimSolver.AttemptStep(ctx, claim, game.AgreeWithClaimLevel(claim))
if err != nil {
return nil, err
}
return &Action{
Type: ActionTypeStep,
ParentIdx: step.LeafClaim.ContractIndex,
IsAttack: step.IsAttack,
PreState: step.PreState,
ProofData: step.ProofData,
OracleData: step.OracleData,
}, nil
}
func (s *GameSolver) calculateMove(ctx context.Context, game types.Game, claim types.Claim) (*Action, error) {
move, err := s.claimSolver.NextMove(ctx, claim, game.AgreeWithClaimLevel(claim))
if err != nil {
return nil, fmt.Errorf("failed to calculate next move for claim index %v: %w", claim.ContractIndex, err)
}
if move == nil || game.IsDuplicate(*move) {
return nil, nil
}
return &Action{
Type: ActionTypeMove,
IsAttack: !move.DefendsParent(),
ParentIdx: move.ParentContractIndex,
Value: move.Value,
}, nil
}
package solver
import (
"context"
"encoding/hex"
"testing"
faulttest "github.com/ethereum-optimism/optimism/op-challenger/game/fault/test"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
type actionMaker func(game types.Game) Action
func TestCalculateNextActions(t *testing.T) {
maxDepth := 4
claimBuilder := faulttest.NewAlphabetClaimBuilder(t, maxDepth)
attackClaim := func(parentIdx int) actionMaker {
return func(game types.Game) Action {
parentClaim := game.Claims()[parentIdx]
return Action{
Type: ActionTypeMove,
ParentIdx: parentIdx,
IsAttack: true,
Value: claimBuilder.CorrectClaimAtPosition(parentClaim.Position.Attack()),
}
}
}
defendClaim := func(parentIdx int) actionMaker {
return func(game types.Game) Action {
parentClaim := game.Claims()[parentIdx]
return Action{
Type: ActionTypeMove,
ParentIdx: parentIdx,
IsAttack: false,
Value: claimBuilder.CorrectClaimAtPosition(parentClaim.Position.Defend()),
}
}
}
stepAttack := func(parentIdx int) actionMaker {
return func(game types.Game) Action {
parentClaim := game.Claims()[parentIdx]
traceIdx := parentClaim.Position.TraceIndex(maxDepth)
return Action{
Type: ActionTypeStep,
ParentIdx: parentIdx,
IsAttack: true,
PreState: claimBuilder.CorrectPreState(traceIdx),
ProofData: claimBuilder.CorrectProofData(traceIdx),
OracleData: claimBuilder.CorrectOracleData(traceIdx),
}
}
}
stepDefend := func(parentIdx int) actionMaker {
return func(game types.Game) Action {
parentClaim := game.Claims()[parentIdx]
traceIdx := parentClaim.Position.TraceIndex(maxDepth) + 1
return Action{
Type: ActionTypeStep,
ParentIdx: parentIdx,
IsAttack: false,
PreState: claimBuilder.CorrectPreState(traceIdx),
ProofData: claimBuilder.CorrectProofData(traceIdx),
OracleData: claimBuilder.CorrectOracleData(traceIdx),
}
}
}
tests := []struct {
name string
agreeWithOutputRoot bool
rootClaimCorrect bool
setupGame func(builder *faulttest.GameBuilder)
expectedActions []actionMaker
}{
{
name: "AttackRootClaim",
agreeWithOutputRoot: true,
setupGame: func(builder *faulttest.GameBuilder) {},
expectedActions: []actionMaker{
attackClaim(0),
},
},
{
name: "DoNotAttackRootClaimWhenDisagreeWithOutputRoot",
agreeWithOutputRoot: false,
setupGame: func(builder *faulttest.GameBuilder) {},
expectedActions: nil,
},
{
// Note: The fault dispute game contract should prevent a correct root claim from actually being posted
// But for completeness, test we ignore it so we don't get sucked into playing an unwinnable game.
name: "DoNotAttackCorrectRootClaim_AgreeWithOutputRoot",
agreeWithOutputRoot: true,
rootClaimCorrect: true,
setupGame: func(builder *faulttest.GameBuilder) {},
expectedActions: nil,
},
{
// Note: The fault dispute game contract should prevent a correct root claim from actually being posted
// But for completeness, test we ignore it so we don't get sucked into playing an unwinnable game.
name: "DoNotAttackCorrectRootClaim_DisagreeWithOutputRoot",
agreeWithOutputRoot: false,
rootClaimCorrect: true,
setupGame: func(builder *faulttest.GameBuilder) {},
expectedActions: nil,
},
{
name: "DoNotPerformDuplicateMoves",
agreeWithOutputRoot: true,
setupGame: func(builder *faulttest.GameBuilder) {
// Expected move has already been made.
builder.Seq().AttackCorrect()
},
expectedActions: nil,
},
{
name: "RespondToAllClaimsAtDisagreeingLevel",
agreeWithOutputRoot: true,
setupGame: func(builder *faulttest.GameBuilder) {
honestClaim := builder.Seq().AttackCorrect() // 1
honestClaim.AttackCorrect() // 2
honestClaim.DefendCorrect() // 3
honestClaim.Attack(common.Hash{0xaa}) // 4
honestClaim.Attack(common.Hash{0xbb}) // 5
honestClaim.Defend(common.Hash{0xcc}) // 6
honestClaim.Defend(common.Hash{0xdd}) // 7
},
expectedActions: []actionMaker{
// Defend the correct claims
defendClaim(2),
defendClaim(3),
// Attack the incorrect claims
attackClaim(4),
attackClaim(5),
attackClaim(6),
attackClaim(7),
},
},
{
name: "StepAtMaxDepth",
agreeWithOutputRoot: true,
setupGame: func(builder *faulttest.GameBuilder) {
lastHonestClaim := builder.Seq().
AttackCorrect(). // 1 - Honest
AttackCorrect(). // 2 - Dishonest
DefendCorrect() // 3 - Honest
lastHonestClaim.AttackCorrect() // 4 - Dishonest
lastHonestClaim.Attack(common.Hash{0xdd}) // 5 - Dishonest
},
expectedActions: []actionMaker{
stepDefend(4),
stepAttack(5),
},
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
builder := claimBuilder.GameBuilder(test.agreeWithOutputRoot, test.rootClaimCorrect)
test.setupGame(builder)
game := builder.Game
for i, claim := range game.Claims() {
t.Logf("Claim %v: Pos: %v ParentIdx: %v, Countered: %v, Value: %v", i, claim.Position.ToGIndex(), claim.ParentContractIndex, claim.Countered, claim.Value)
}
solver := NewGameSolver(maxDepth, claimBuilder.CorrectTraceProvider())
actions, err := solver.CalculateNextActions(context.Background(), game)
require.NoError(t, err)
for i, action := range actions {
t.Logf("Move %v: Type: %v, ParentIdx: %v, Attack: %v, Value: %v, PreState: %v, ProofData: %v",
i, action.Type, action.ParentIdx, action.IsAttack, action.Value, hex.EncodeToString(action.PreState), hex.EncodeToString(action.ProofData))
}
require.Len(t, actions, len(test.expectedActions))
for i, action := range test.expectedActions {
require.Containsf(t, actions, action(game), "Expected claim %v missing", i)
}
})
}
}
......@@ -15,22 +15,22 @@ var (
ErrStepAgreedClaim = errors.New("cannot step on claims we agree with")
)
// Solver uses a [TraceProvider] to determine the moves to make in a dispute game.
type Solver struct {
// claimSolver uses a [TraceProvider] to determine the moves to make in a dispute game.
type claimSolver struct {
trace types.TraceProvider
gameDepth int
}
// NewSolver creates a new [Solver] using the provided [TraceProvider].
func NewSolver(gameDepth int, traceProvider types.TraceProvider) *Solver {
return &Solver{
// newClaimSolver creates a new [claimSolver] using the provided [TraceProvider].
func newClaimSolver(gameDepth int, traceProvider types.TraceProvider) *claimSolver {
return &claimSolver{
traceProvider,
gameDepth,
}
}
// NextMove returns the next move to make given the current state of the game.
func (s *Solver) NextMove(ctx context.Context, claim types.Claim, agreeWithClaimLevel bool) (*types.Claim, error) {
func (s *claimSolver) NextMove(ctx context.Context, claim types.Claim, agreeWithClaimLevel bool) (*types.Claim, error) {
if agreeWithClaimLevel {
return nil, nil
}
......@@ -58,7 +58,7 @@ type StepData struct {
// AttemptStep determines what step should occur for a given leaf claim.
// An error will be returned if the claim is not at the max depth.
func (s *Solver) AttemptStep(ctx context.Context, claim types.Claim, agreeWithClaimLevel bool) (StepData, error) {
func (s *claimSolver) AttemptStep(ctx context.Context, claim types.Claim, agreeWithClaimLevel bool) (StepData, error) {
if claim.Depth() != s.gameDepth {
return StepData{}, ErrStepNonLeafNode
}
......@@ -100,7 +100,7 @@ func (s *Solver) AttemptStep(ctx context.Context, claim types.Claim, agreeWithCl
}
// attack returns a response that attacks the claim.
func (s *Solver) attack(ctx context.Context, claim types.Claim) (*types.Claim, error) {
func (s *claimSolver) attack(ctx context.Context, claim types.Claim) (*types.Claim, error) {
position := claim.Attack()
value, err := s.traceAtPosition(ctx, position)
if err != nil {
......@@ -114,7 +114,7 @@ func (s *Solver) attack(ctx context.Context, claim types.Claim) (*types.Claim, e
}
// defend returns a response that defends the claim.
func (s *Solver) defend(ctx context.Context, claim types.Claim) (*types.Claim, error) {
func (s *claimSolver) defend(ctx context.Context, claim types.Claim) (*types.Claim, error) {
if claim.IsRoot() {
return nil, nil
}
......@@ -131,13 +131,13 @@ func (s *Solver) defend(ctx context.Context, claim types.Claim) (*types.Claim, e
}
// agreeWithClaim returns true if the claim is correct according to the internal [TraceProvider].
func (s *Solver) agreeWithClaim(ctx context.Context, claim types.ClaimData) (bool, error) {
func (s *claimSolver) agreeWithClaim(ctx context.Context, claim types.ClaimData) (bool, error) {
ourValue, err := s.traceAtPosition(ctx, claim.Position)
return bytes.Equal(ourValue[:], claim.Value[:]), err
}
// traceAtPosition returns the [common.Hash] from internal [TraceProvider] at the given [Position].
func (s *Solver) traceAtPosition(ctx context.Context, p types.Position) (common.Hash, error) {
func (s *claimSolver) traceAtPosition(ctx context.Context, p types.Position) (common.Hash, error) {
index := p.TraceIndex(s.gameDepth)
hash, err := s.trace.Get(ctx, index)
return hash, err
......
package solver_test
package solver
import (
"context"
"errors"
"testing"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/solver"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/test"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/stretchr/testify/require"
......@@ -84,7 +83,7 @@ func TestNextMove(t *testing.T) {
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
solver := solver.NewSolver(maxDepth, builder.CorrectTraceProvider())
solver := newClaimSolver(maxDepth, builder.CorrectTraceProvider())
move, err := solver.NextMove(context.Background(), test.claim, test.agreeWithLevel)
if test.expectedErr == nil {
require.NoError(t, err)
......@@ -174,19 +173,19 @@ func TestAttemptStep(t *testing.T) {
{
name: "CannotStepNonLeaf",
claim: builder.Seq(false).Attack(false).Get(),
expectedErr: solver.ErrStepNonLeafNode,
expectedErr: ErrStepNonLeafNode,
},
{
name: "CannotStepAgreedNode",
claim: builder.Seq(false).Attack(false).Get(),
agreeWithLevel: true,
expectedErr: solver.ErrStepNonLeafNode,
expectedErr: ErrStepNonLeafNode,
},
{
name: "CannotStepAgreedNode",
claim: builder.Seq(false).Attack(false).Get(),
agreeWithLevel: true,
expectedErr: solver.ErrStepNonLeafNode,
expectedErr: ErrStepNonLeafNode,
},
}
......@@ -198,7 +197,7 @@ func TestAttemptStep(t *testing.T) {
alphabetProvider = test.NewAlphabetWithProofProvider(t, maxDepth, errProvider)
}
builder = test.NewClaimBuilder(t, maxDepth, alphabetProvider)
alphabetSolver := solver.NewSolver(maxDepth, builder.CorrectTraceProvider())
alphabetSolver := newClaimSolver(maxDepth, builder.CorrectTraceProvider())
step, err := alphabetSolver.AttemptStep(ctx, tableTest.claim, tableTest.agreeWithLevel)
if tableTest.expectedErr == nil {
require.NoError(t, err)
......@@ -212,7 +211,7 @@ func TestAttemptStep(t *testing.T) {
require.Equal(t, tableTest.expectedOracleData.OracleOffset, step.OracleData.OracleOffset)
} else {
require.ErrorIs(t, err, tableTest.expectedErr)
require.Equal(t, solver.StepData{}, step)
require.Equal(t, StepData{}, step)
}
})
}
......
......@@ -38,6 +38,13 @@ func (c *ClaimBuilder) CorrectClaim(idx uint64) common.Hash {
return value
}
// CorrectClaimAtPosition returns the canonical claim at a specified position
func (c *ClaimBuilder) CorrectClaimAtPosition(pos types.Position) common.Hash {
value, err := c.correct.Get(context.Background(), pos.TraceIndex(c.maxDepth))
c.require.NoError(err)
return value
}
// CorrectPreState returns the pre-state (not hashed) required to execute the valid step at the specified trace index
func (c *ClaimBuilder) CorrectPreState(idx uint64) []byte {
preimage, _, _, err := c.correct.GetStepData(context.Background(), idx)
......@@ -103,6 +110,19 @@ func (c *ClaimBuilder) AttackClaim(claim types.Claim, correct bool) types.Claim
Position: pos,
},
Parent: claim.ClaimData,
ParentContractIndex: claim.ContractIndex,
}
}
func (c *ClaimBuilder) AttackClaimWithValue(claim types.Claim, value common.Hash) types.Claim {
pos := claim.Position.Attack()
return types.Claim{
ClaimData: types.ClaimData{
Value: value,
Position: pos,
},
Parent: claim.ClaimData,
ParentContractIndex: claim.ContractIndex,
}
}
......@@ -114,5 +134,18 @@ func (c *ClaimBuilder) DefendClaim(claim types.Claim, correct bool) types.Claim
Position: pos,
},
Parent: claim.ClaimData,
ParentContractIndex: claim.ContractIndex,
}
}
func (c *ClaimBuilder) DefendClaimWithValue(claim types.Claim, value common.Hash) types.Claim {
pos := claim.Position.Defend()
return types.Claim{
ClaimData: types.ClaimData{
Value: value,
Position: pos,
},
Parent: claim.ClaimData,
ParentContractIndex: claim.ContractIndex,
}
}
package test
import (
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum/go-ethereum/common"
)
type GameBuilder struct {
builder *ClaimBuilder
Game types.Game
}
func (c *ClaimBuilder) GameBuilder(agreeWithOutputRoot bool, rootCorrect bool) *GameBuilder {
return &GameBuilder{
builder: c,
Game: types.NewGameState(agreeWithOutputRoot, c.CreateRootClaim(rootCorrect), uint64(c.maxDepth)),
}
}
type GameBuilderSeq struct {
builder *ClaimBuilder
lastClaim types.Claim
game types.Game
}
func (g *GameBuilder) Seq() *GameBuilderSeq {
return &GameBuilderSeq{
builder: g.builder,
game: g.Game,
lastClaim: g.Game.Claims()[0],
}
}
func (s *GameBuilderSeq) AttackCorrect() *GameBuilderSeq {
claim := s.builder.AttackClaim(s.lastClaim, true)
claim.ContractIndex = len(s.game.Claims())
s.builder.require.NoError(s.game.Put(claim))
return &GameBuilderSeq{
builder: s.builder,
game: s.game,
lastClaim: claim,
}
}
func (s *GameBuilderSeq) Attack(value common.Hash) *GameBuilderSeq {
claim := s.builder.AttackClaimWithValue(s.lastClaim, value)
claim.ContractIndex = len(s.game.Claims())
s.builder.require.NoError(s.game.Put(claim))
return &GameBuilderSeq{
builder: s.builder,
game: s.game,
lastClaim: claim,
}
}
func (s *GameBuilderSeq) DefendCorrect() *GameBuilderSeq {
claim := s.builder.DefendClaim(s.lastClaim, true)
claim.ContractIndex = len(s.game.Claims())
s.builder.require.NoError(s.game.Put(claim))
return &GameBuilderSeq{
builder: s.builder,
game: s.game,
lastClaim: claim,
}
}
func (s *GameBuilderSeq) Defend(value common.Hash) *GameBuilderSeq {
claim := s.builder.DefendClaimWithValue(s.lastClaim, value)
claim.ContractIndex = len(s.game.Claims())
s.builder.require.NoError(s.game.Put(claim))
return &GameBuilderSeq{
builder: s.builder,
game: s.game,
lastClaim: claim,
}
}
......@@ -18,31 +18,33 @@ func NewPositionFromGIndex(x uint64) Position {
return NewPosition(depth, int(indexAtDepth))
}
func (p *Position) Depth() int {
func (p Position) Depth() int {
return p.depth
}
func (p *Position) IndexAtDepth() int {
func (p Position) IndexAtDepth() int {
return p.indexAtDepth
}
func (p *Position) IsRootPosition() bool {
func (p Position) IsRootPosition() bool {
return p.depth == 0 && p.indexAtDepth == 0
}
// TraceIndex calculates the what the index of the claim value would be inside the trace.
// It is equivalent to going right until the final depth has been reached.
func (p *Position) TraceIndex(maxDepth int) uint64 {
func (p Position) TraceIndex(maxDepth int) uint64 {
// When we go right, we do a shift left and set the bottom bit to be 1.
// To do this in a single step, do all the shifts at once & or in all 1s for the bottom bits.
rd := maxDepth - p.depth
return uint64(p.indexAtDepth<<rd | ((1 << rd) - 1))
}
// move goes to the left or right child.
func (p *Position) move(right bool) {
p.depth++
p.indexAtDepth = (p.indexAtDepth << 1) | boolToInt(right)
// move returns a new position at the left or right child.
func (p Position) move(right bool) Position {
return Position{
depth: p.depth + 1,
indexAtDepth: (p.indexAtDepth << 1) | boolToInt(right),
}
}
func boolToInt(b bool) int {
......@@ -53,33 +55,29 @@ func boolToInt(b bool) int {
}
}
// parent moves up to the parent.
func (p *Position) parent() {
p.depth--
p.indexAtDepth = p.indexAtDepth >> 1
// parent return a new position that is the parent of this Position.
func (p Position) parent() Position {
return Position{
depth: p.depth - 1,
indexAtDepth: p.indexAtDepth >> 1,
}
}
// Attack creates a new position which is the attack position of this one.
func (p *Position) Attack() Position {
p2 := NewPosition(p.depth, p.indexAtDepth)
p2.move(false)
return p2
func (p Position) Attack() Position {
return p.move(false)
}
// Defend creates a new position which is the defend position of this one.
func (p *Position) Defend() Position {
p2 := NewPosition(p.depth, p.indexAtDepth)
p2.parent()
p2.move(true)
p2.move(false)
return p2
func (p Position) Defend() Position {
return p.parent().move(true).move(false)
}
func (p *Position) Print(maxDepth int) {
func (p Position) Print(maxDepth int) {
fmt.Printf("GIN: %4b\tTrace Position is %4b\tTrace Depth is: %d\tTrace Index is: %d\n", p.ToGIndex(), p.indexAtDepth, p.depth, p.TraceIndex(maxDepth))
}
func (p *Position) ToGIndex() uint64 {
func (p Position) ToGIndex() uint64 {
return uint64(1<<p.depth | p.indexAtDepth)
}
......
......@@ -62,5 +62,7 @@ done
# Root claim commits to the entire trace.
# Alphabet game claim construction: keccak256(abi.encode(trace_index, trace[trace_index]))
ROOT_CLAIM=$(cast keccak $(cast abi-encode "f(uint256,uint256)" 15 122))
# Replace the first byte of the claim with the invalid vm status indicator
ROOT_CLAIM="0x01${ROOT_CLAIM:4:60}"
GAME_TYPE=255 ${SOURCE_DIR}/../create_game.sh http://localhost:8545 "${DISPUTE_GAME_FACTORY}" "${ROOT_CLAIM}" --private-key "${DEVNET_SPONSOR}"
......@@ -32,10 +32,10 @@ RUN mkdir manifests && \
FROM us-docker.pkg.dev/oplabs-tools-artifacts/images/ci-builder:latest as foundry
# bullseye-slim is debian based
# we use it rather than alpien because it's not much
# we use it rather than alpine because it's not much
# bigger and alpine is often missing packages for node applications
# alpine is not officially supported by node.js
FROM node:16.16.0-bullseye-slim as base
FROM node:18.17.1-bullseye-slim as base
# Base: install deps
RUN apt-get update && apt-get install -y \
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -6,7 +6,7 @@ require (
github.com/BurntSushi/toml v1.2.0
github.com/alicebob/miniredis v2.5.0+incompatible
github.com/emirpasic/gods v1.18.1
github.com/ethereum/go-ethereum v1.12.0
github.com/ethereum/go-ethereum v1.12.1
github.com/go-redis/redis/v8 v8.11.4
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb
github.com/gorilla/mux v1.8.0
......@@ -17,7 +17,7 @@ require (
github.com/rs/cors v1.8.2
github.com/stretchr/testify v1.8.1
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
golang.org/x/sync v0.1.0
golang.org/x/sync v0.3.0
gopkg.in/yaml.v3 v3.0.1
)
......@@ -26,6 +26,7 @@ require (
github.com/VictoriaMetrics/fastcache v1.9.0 // indirect
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.7.0 // indirect
github.com/btcsuite/btcd v0.22.0-beta // indirect
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
......@@ -33,12 +34,14 @@ require (
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 // indirect
github.com/cockroachdb/redact v1.1.3 // indirect
github.com/consensys/bavard v0.1.13 // indirect
github.com/consensys/gnark-crypto v0.10.0 // indirect
github.com/crate-crypto/go-kzg-4844 v0.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/deckarep/golang-set/v2 v2.1.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
github.com/ethereum/c-kzg-4844 v0.3.0 // indirect
github.com/getsentry/sentry-go v0.18.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-stack/stack v1.8.1 // indirect
......@@ -46,16 +49,14 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/gomodule/redigo v1.8.8 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c // indirect
github.com/huin/goupnp v1.0.3 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/holiman/uint256 v1.2.3 // indirect
github.com/klauspost/compress v1.15.15 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mmcloughlin/addchain v0.4.0 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
......@@ -64,16 +65,16 @@ require (
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/status-im/keycard-go v0.2.0 // indirect
github.com/supranational/blst v0.3.11 // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/tklauser/numcpus v0.4.0 // indirect
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/crypto v0.1.0 // indirect
golang.org/x/exp v0.0.0-20230206171751-46f607a40771 // indirect
golang.org/x/sys v0.7.0 // indirect
golang.org/x/text v0.8.0 // indirect
golang.org/x/crypto v0.9.0 // indirect
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect
golang.org/x/sys v0.9.0 // indirect
golang.org/x/text v0.9.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
rsc.io/tmplfunc v0.0.3 // indirect
)
......@@ -23,6 +23,8 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bits-and-blooms/bitset v1.7.0 h1:YjAGVd3XmtK9ktAbX8Zg2g2PwLIMjGREZJHlV4j7NEo=
github.com/bits-and-blooms/bitset v1.7.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btcd v0.22.0-beta h1:LTDpDKUM5EeOFBPM8IXpinEcmZ6FWfNZbE3lfrfdnWo=
github.com/btcsuite/btcd v0.22.0-beta/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA=
......@@ -39,7 +41,6 @@ github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
......@@ -60,12 +61,16 @@ github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811/go.mod h1:Nb5lg
github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ=
github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ=
github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
github.com/consensys/gnark-crypto v0.10.0 h1:zRh22SR7o4K35SoNqouS9J/TKHTyU2QWaj5ldehyXtA=
github.com/consensys/gnark-crypto v0.10.0/go.mod h1:Iq/P3HHl0ElSjsg2E1gsMwhAyxnxoKK5nVyZKd+/KhU=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/crate-crypto/go-kzg-4844 v0.3.0 h1:UBlWE0CgyFqqzTI+IFyCzA7A3Zw4iip6uzRv5NIXG0A=
github.com/crate-crypto/go-kzg-4844 v0.3.0/go.mod h1:SBP7ikXEgDnUPONgm33HtuDZEDtWa3L4QtN1ocJSEQ4=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
......@@ -91,18 +96,16 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/ethereum/go-ethereum v1.12.0 h1:bdnhLPtqETd4m3mS8BGMNvBTf36bO5bx/hxE2zljOa0=
github.com/ethereum/go-ethereum v1.12.0/go.mod h1:/oo2X/dZLJjf2mJ6YT9wcWxa4nNJDBKDBU6sFIpx1Gs=
github.com/ethereum/c-kzg-4844 v0.3.0 h1:3Y3hD6l5i0dEYsBL50C+Om644kve3pNqoAcvE26o9zI=
github.com/ethereum/c-kzg-4844 v0.3.0/go.mod h1:WI2Nd82DMZAAZI1wV2neKGost9EKjvbpQR9OqE5Qqa8=
github.com/ethereum/go-ethereum v1.12.1 h1:1kXDPxhLfyySuQYIfRxVBGYuaHdxNNxevA73vjIwsgk=
github.com/ethereum/go-ethereum v1.12.1/go.mod h1:zKetLweqBR8ZS+1O9iJWI8DvmmD2NzD19apjEWDCsnw=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI=
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c=
github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0=
github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ=
......@@ -130,9 +133,7 @@ github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
......@@ -165,28 +166,23 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c h1:DZfsyhDK1hnSS5lH8l+JggqzEleHteTYfutAiVlSUM8=
github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw=
github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o=
github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ=
github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y=
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE=
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
......@@ -195,8 +191,6 @@ github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/
github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk=
github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g=
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
......@@ -228,17 +222,16 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
......@@ -249,8 +242,9 @@ github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A=
github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU=
github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
......@@ -304,9 +298,7 @@ github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZV
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U=
github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
......@@ -321,8 +313,6 @@ github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tL
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA=
github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
......@@ -335,19 +325,18 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4=
github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw=
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o=
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q=
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
......@@ -358,7 +347,6 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
......@@ -381,11 +369,11 @@ golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20230206171751-46f607a40771 h1:xP7rWLUr1e1n2xkK5YB4LI0hPEy3LJC6Wk+D4pGlOJg=
golang.org/x/exp v0.0.0-20230206171751-46f607a40771/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU=
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
......@@ -415,7 +403,7 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
......@@ -425,8 +413,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
......@@ -459,9 +447,8 @@ golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
......@@ -469,8 +456,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
......@@ -526,7 +513,6 @@ gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
......@@ -544,3 +530,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=
rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=
......@@ -29,8 +29,9 @@ that maintains 1:1 compatibility with Ethereum.
Specifications of new features in active development.
- [Fault Proof](./fault-proof.md)
- [Dispute Game](./dispute-game.md)
- [Dispute Game Interface](./dispute-game-interface.md)
- [Fault Dispute Game](./fault-dispute-game.md)
- [Cannon VM](./cannon-fault-proof-vm.md)
## Design Goals
......
......@@ -20,14 +20,14 @@ be attached to an output proposal. In this case, the bond will be paid in ether.
By requiring a bond to be posted with an output proposal, spam and invalid outputs
are disincentivized. Explicitly, if invalid outputs are proposed, challenge agents
can delete the invalid output via a [dispute-game](./dispute-game.md) and seize the
can delete the invalid output via a [dispute-game](./dispute-game-interface.md) and seize the
proposer's bond. So, posting invalid outputs is directly disincentivized in this way
since the proposer would lose their bond if the challenge agents seize it.
Concretely, outputs will be permissionlessly proposed to the `L2OutputOracle` contract.
When submitting an output proposal, the ether value is sent as the bond. This bond is
then held by a bond manager contract. The bond manager contract is responsible for
both the [dispute-games](./dispute-game.md) and the `L2OutputOracle` (further detailed
both the [dispute-games](./dispute-game-interface.md) and the `L2OutputOracle` (further detailed
in [proposals](./proposals.md)).
The bond manager will need to handle bond logic for a variety of different
......@@ -136,7 +136,7 @@ instead tied to the address of the output proposer.
## Bond Manager Implementation
Initially, the bond manager will only be used by the `L2OutputOracle` contract
for output proposals in the attestation [dispute game](./dispute-game.md). Since
for output proposals in the attestation [dispute game](./dispute-game-interface.md). Since
the attestation dispute game has a permissioned set of attestors, there are no
intermediate steps in the game that would require bonds.
......
# Challenger Specification
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents**
- [Description](#description)
- [Terminology](#terminology)
- [Event and Response Lifecycle](#event-and-response-lifecycle)
- [`GameType.FAULT`](#gametypefault)
- [`GameType.ATTESTATION`](#gametypeattestation)
- [`GameType.VALIDITY`](#gametypevalidity)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Description
The Challenger is an off-chain agent that listens for faulty claims made about the state of
the L2 on the data availability layer. It is responsible for challenging these incorrect claims
and ensuring the correctness of all finalized claims on the settlement layer.
The Challenger agent is intended to be ran as a permissionless service by participants of the network
alongside a [rollup-node](./rollup-node.md). Challenger agents will be rewarded in the form of the
bond attached to the claims they disprove.
## Terminology
- **data availability layer** - In the context of this document, the data availability layer is the
generic term for the location where claims about the state of the layer two are made. In the context
of Optimism, this is Ethereum Mainnet.
- **settlement layer** - In the context of this document, the settlement layer is the location of the
bridge as well as where funds deposited to the rollup reside. In the context of Optimism, this is
Ethereum Mainnet.
- **L2** - In the context of this document, the layer two of the Optimistic Rollup. In the context
of Optimism, this is the Optimism Mainnet.
- **rollup-node** - In the context of this document, the rollup node describes the
[rollup-node specification](./rollup-node.md). In the context of Optimism, this is the implementation
of the [rollup-node specification](./rollup-node.md), the `op-node`.
## Event and Response Lifecycle
The Challenger agent is expected to be able to listen for and respond to several different events
on the data availability layer. These events and responses are parameterized depending on the type
of dispute game being played, and the Challenger listens to different events and responds uniquely
to each of the different game types. For specification of dispute game types, see the
[Dispute Game Interfaces specification](./dispute-game-interface.md) and
[Dispute Game specification](./dispute-game.md).
### `GameType.FAULT`
> **Warning**
> The `FAULT` game type is not yet implemented. In the first iteration of Optimism's decentralization effort,
> challengers will respond to `ATTESTATION` games only.
**Events and Responses**
*TODO*
### `GameType.ATTESTATION`
**Events and Responses**
- [`L2OutputOracle.OutputProposed`](../packages/contracts-bedrock/src/L1/L2OutputOracle.sol#L57-70)
The `L2OutputOracle` contract emits this event when a new output is proposed on the data availability
layer. Each time an output is proposed, the Challenger should check to see if the output is equal
the output given by the `optimism_outputAtBlock` endpoint of their `rollup-node`.
- If it is, the Challenger should do nothing to challenge this output proposal.
- If it is not, the Challenger should respond by creating a new `DisputeGame` with the
`DisputeGameType.ATTESTATION` `gameType`, the correct output root as the `rootClaim`, and the abi-encoded
`l2BlockNumber` of the correct output root as the `extraData`.
![Attestation `OutputProposed` Diagram](./assets/challenger_attestation_output_proposed.png)
- `DisputeGameFactory.DisputeGameCreated` A new dispute game has been created and is ready to be reviewed. The
Challenger agent should listen for this event and check if the `rootClaim` of the `AttestationDisputeGame`
created by the `DisputeGameFactory` is equal to the output root of their `rollup-node` at the game's `l2BlockNumber`.
- If it is, the Challenger should sign the [EIP-712 typeHash](./dispute-game.md) of the struct containing the
`AttestationDisputeGame`'s `rootClaim` and `l2BlockNumber`. The Challenger should then submit the abi-encoded
signature to the `AttestationDisputeGame`'s `challenge` function.
- If it is not, the Challenger should do nothing in support of this dispute game.
![Attestation `DisputeGameCreated` Diagram](./assets/challenger_attestation_dispute_game_created.png)
A full diagram and lifecycle of the Challenger's role in the `ATTESTATION` game type can be found below:
![Attestation Diagram](./assets/challenger_attestation.png)
### `GameType.VALIDITY`
**TODO**
> **Warning**
> The `VALIDITY` game type is not yet implemented. In the first iteration of Optimism's decentralization effort,
> challengers will respond to `ATTESTATION` games only. A validity proof based dispute game is a possibility,
> but fault proof based dispute games will be the primary focus of the team in the near future.
**Events and Responses**
*TODO*
# Dispute Game
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents**
- [Attestation Dispute Game](#attestation-dispute-game)
- [Smart Contract Implementation](#smart-contract-implementation)
- [Attestation Structure](#attestation-structure)
- [Why EIP-712](#why-eip-712)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Attestation Dispute Game
The output attestation based dispute game shifts the current permissioned output proposal process
to a permissionless, social-consensus based architecture that can progressively decentralize over
time by increasing the size of the signer set. In this "game," output proposals can be submitted
permissionlessly. To prevent "invalid output proposals," a social quorum can revert an output proposal
when an invalid one is discovered. The set of signers is maintained in the `SystemConfig` contract,
and these signers will issue [EIP-712](https://eips.ethereum.org/EIPS/eip-712) signatures
over canonical output roots and the `l2BlockNumber`s they commit to as attestations. To learn more,
see the [DisputeGame Interface Spec](./dispute-game-interface.md).
In the above language, an "invalid output proposal" is defined as an output proposal that represents
a non-canonical state of the L2 chain.
### Smart Contract Implementation
The `AttestationDisputeGame` should implement the `IDisputeGame` interface and also be able to call
out to the `L2OutputOracle`. It is expected that the `L2OutputOracle` will grant permissions to
`AttestationDisputeGame` contracts to call its `deleteL2Outputs` function at the *specific* `l2BlockNumber`
that is embedded in the `AttestationDisputeGame`'s `extraData`.
The `AttestationDisputeGame` should be configured with a quorum ratio at deploy time. It should also
maintain a set of attestor accounts, which is fetched by the `SystemConfig` contract and snapshotted
at deploy time. This snapshot is necessary to have a fixed upper bound on resolution cost, which in
turn gives a fix cost for the necessary bond attached to output proposals.
The ability to add and remove attestor accounts should be enabled by a single immutable
account that controls the `SystemConfig`. It should be impossible to remove accounts such that quorum
is not able to be reached. It is ok to allow accounts to be added or removed in the middle of an
open challenge, as it will not affect the `signerSet` that exists within open challenges.
A challenge is created when an alternative output root for a given `l2BlockNumber` is presented to the
`DisputeGameFactory` contract. Multiple challenges should be able to run in parallel.
For simplicity, the `AttestationDisputeGame` does not need to track what output proposals are
committed to as part of the attestations. It only needs to check that the attested output root
is different than the proposed output root. If this is not checked, then it will be possible
to remove output proposals that are in agreement with the attestations and create a griefing vector.
#### Attestation Structure
The EIP-712 [typeHash](https://eips.ethereum.org/EIPS/eip-712#rationale-for-typehash) should be
defined as the following:
```solidity
TYPE_HASH = keccak256("Dispute(bytes32 outputRoot,uint256 l2BlockNumber)");
```
The components for the `typeHash` are as follows:
- `outputRoot` - The **correct** output root that commits to the given `l2BlockNumber`. This should be a
positive attestation where the `rootClaim` of the `AttestationDisputeGame` is the **correct** output root
for the given `l2BlockNumber`.
- `l2BlockNumber` - The L2 block number that the `outputRoot` commits to. The `outputRoot` should commit
to the entirety of the L2 state from genesis up to and including this `l2BlockNumber`.
### Why EIP-712
It is important to use EIP-712 to decouple the originator of the transaction and the attestor. This
will allow a decentralized network of attestors that serve attestations to bots that are responsible
for ensuring that all output proposals submitted to the network will not allow for malicious withdrawals
from the bridge.
It is important to have replay protection to ensure that attestations cannot be used more than once.
......@@ -412,5 +412,5 @@ The allocated response time is limited by the dispute-game window,
and any additional time necessary based on L1 fee changes when bonds are insufficient.
> Note: the timed, bonded, bisection dispute game is in development.
> Also see [dispute-game specs](./dispute-game.md) for general dispute game system specifications,
> Also see [fault dispute-game specs](./fault-dispute-game.md) for fault dispute game system specifications,
> And [dispute-game-interface specs](./dispute-game-interface.md) for dispute game interface specifications.
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