diff --git a/.coderabbit.yml b/.coderabbit.yml index 6e33cda85da87..f54403cf1571e 100644 --- a/.coderabbit.yml +++ b/.coderabbit.yml @@ -7,7 +7,6 @@ reviews: collapse_walkthrough: true path_filters: - "!**/*.json" - - "!op-bindings/bindings/**" path_instructions: - path: "**.sol" instructions: "Focus on the following areas: diff --git a/.github/mergify.yml b/.github/mergify.yml index 2b8627818b958..c95e05bfdaced 100644 --- a/.github/mergify.yml +++ b/.github/mergify.yml @@ -96,13 +96,6 @@ pull_request_rules: label: add: - A-op-batcher - - name: Add A-op-bindings label - conditions: - - 'files~=^op-bindings/' - actions: - label: - add: - - A-op-bindings - name: Add A-op-bootnode label conditions: - 'files~=^op-bootnode/' diff --git a/.gitignore b/.gitignore index 54c16a1f67c3f..338b1fab08ef8 100644 --- a/.gitignore +++ b/.gitignore @@ -40,8 +40,6 @@ packages/contracts-bedrock/deployments/anvil coverage.out -# Ignore bedrock go bindings local output files -op-bindings/bin __pycache__ diff --git a/.semgrepignore b/.semgrepignore index ae209efea25d5..5653a627ce838 100644 --- a/.semgrepignore +++ b/.semgrepignore @@ -18,7 +18,6 @@ tests/ # Semgrep-action log folder .semgrep_logs/ -op-bindings/bindings/ packages/*/node_modules packages/*/test diff --git a/Makefile b/Makefile index d38e5f8c37d07..1f7f916674086 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,10 @@ lint-go: golangci-lint run -E goimports,sqlclosecheck,bodyclose,asciicheck,misspell,errorlint --timeout 5m -e "errors.As" -e "errors.Is" ./... .PHONY: lint-go +lint-go-fix: + golangci-lint run -E goimports,sqlclosecheck,bodyclose,asciicheck,misspell,errorlint --timeout 5m -e "errors.As" -e "errors.Is" ./... --fix +.PHONY: lint-go-fix + build-ts: submodules if [ -f "$$NVM_DIR/nvm.sh" ]; then \ . $$NVM_DIR/nvm.sh && nvm use; \ @@ -101,9 +105,6 @@ submodules: git submodule update --init --recursive .PHONY: submodules -op-bindings: - make -C ./op-bindings -.PHONY: op-bindings op-node: make -C ./op-node op-node diff --git a/codecov.yml b/codecov.yml index d4aeb396dbc11..e8e97e47304ff 100644 --- a/codecov.yml +++ b/codecov.yml @@ -9,7 +9,6 @@ comment: ignore: - "op-e2e" - - "op-bindings/bindings/*.go" - "**/*.t.sol" - "packages/contracts-bedrock/test/**/*.sol" - "packages/contracts-bedrock/scripts/**/*.sol" diff --git a/go.mod b/go.mod index f3a86389de537..2ddf4c48ddb2e 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/hashicorp/raft v1.7.0 github.com/hashicorp/raft-boltdb v0.0.0-20231211162105-6c830fa4535e - github.com/holiman/uint256 v1.2.4 + github.com/holiman/uint256 v1.3.0 github.com/ipfs/go-datastore v0.6.0 github.com/ipfs/go-ds-leveldb v0.5.0 github.com/klauspost/compress v1.17.9 @@ -39,6 +39,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/pkg/profile v1.7.0 github.com/prometheus/client_golang v1.19.1 + github.com/protolambda/ctxlock v0.1.0 github.com/stretchr/testify v1.9.0 github.com/urfave/cli/v2 v2.27.1 golang.org/x/crypto v0.25.0 diff --git a/go.sum b/go.sum index 9c46fa8713b06..c51dbd5afdfaf 100644 --- a/go.sum +++ b/go.sum @@ -339,8 +339,8 @@ github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6w github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= 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.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= -github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/holiman/uint256 v1.3.0 h1:4wdcm/tnd0xXdu7iS3ruNvxkWwrb4aeBQv19ayYn8F4= +github.com/holiman/uint256 v1.3.0/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= @@ -652,6 +652,8 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/protolambda/ctxlock v0.1.0 h1:rCUY3+vRdcdZXqT07iXgyr744J2DU2LCBIXowYAjBCE= +github.com/protolambda/ctxlock v0.1.0/go.mod h1:vefhX6rIZH8rsg5ZpOJfEDYQOppZi19SfPiGOFrNnwM= github.com/prysmaticlabs/gohashtree v0.0.1-alpha.0.20220714111606-acbb2962fb48 h1:cSo6/vk8YpvkLbk9v3FO97cakNmUoxwi2KMP8hd5WIw= github.com/prysmaticlabs/gohashtree v0.0.1-alpha.0.20220714111606-acbb2962fb48/go.mod h1:4pWaT30XoEx1j8KNJf3TV+E3mQkaufn7mf+jRNb/Fuk= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= diff --git a/op-challenger/config/config_test.go b/op-challenger/config/config_test.go index 56b99378187b5..9c60262c6a761 100644 --- a/op-challenger/config/config_test.go +++ b/op-challenger/config/config_test.go @@ -14,23 +14,23 @@ import ( ) var ( - validL1EthRpc = "http://localhost:8545" - validL1BeaconUrl = "http://localhost:9000" - validGameFactoryAddress = common.Address{0x23} - validCannonBin = "./bin/cannon" - validCannonOpProgramBin = "./bin/op-program" - validCannonNetwork = "mainnet" - validCannonAbsolutPreState = "pre.json" - validCannonAbsolutPreStateBaseURL, _ = url.Parse("http://localhost/foo/") - validDatadir = "/tmp/data" - validL2Rpc = "http://localhost:9545" - validRollupRpc = "http://localhost:8555" - - validAsteriscBin = "./bin/asterisc" - validAsteriscOpProgramBin = "./bin/op-program" - validAsteriscNetwork = "mainnet" - validAsteriscAbsolutPreState = "pre.json" - validAsteriscAbsolutPreStateBaseURL, _ = url.Parse("http://localhost/bar/") + validL1EthRpc = "http://localhost:8545" + validL1BeaconUrl = "http://localhost:9000" + validGameFactoryAddress = common.Address{0x23} + validCannonBin = "./bin/cannon" + validCannonOpProgramBin = "./bin/op-program" + validCannonNetwork = "mainnet" + validCannonAbsolutePreState = "pre.json" + validCannonAbsolutePreStateBaseURL, _ = url.Parse("http://localhost/foo/") + validDatadir = "/tmp/data" + validL2Rpc = "http://localhost:9545" + validRollupRpc = "http://localhost:8555" + + validAsteriscBin = "./bin/asterisc" + validAsteriscOpProgramBin = "./bin/op-program" + validAsteriscNetwork = "mainnet" + validAsteriscAbsolutePreState = "pre.json" + validAsteriscAbsolutePreStateBaseURL, _ = url.Parse("http://localhost/bar/") ) var cannonTraceTypes = []types.TraceType{types.TraceTypeCannon, types.TraceTypePermissioned} @@ -39,14 +39,14 @@ var asteriscTraceTypes = []types.TraceType{types.TraceTypeAsterisc} func applyValidConfigForCannon(cfg *Config) { cfg.Cannon.VmBin = validCannonBin cfg.Cannon.Server = validCannonOpProgramBin - cfg.CannonAbsolutePreStateBaseURL = validCannonAbsolutPreStateBaseURL + cfg.CannonAbsolutePreStateBaseURL = validCannonAbsolutePreStateBaseURL cfg.Cannon.Network = validCannonNetwork } func applyValidConfigForAsterisc(cfg *Config) { cfg.Asterisc.VmBin = validAsteriscBin cfg.Asterisc.Server = validAsteriscOpProgramBin - cfg.AsteriscAbsolutePreStateBaseURL = validAsteriscAbsolutPreStateBaseURL + cfg.AsteriscAbsolutePreStateBaseURL = validAsteriscAbsolutePreStateBaseURL cfg.Asterisc.Network = validAsteriscNetwork } @@ -135,7 +135,7 @@ func TestCannonRequiredArgs(t *testing.T) { t.Run(fmt.Sprintf("TestCannonAbsolutePreState-%v", traceType), func(t *testing.T) { config := validConfig(traceType) - config.CannonAbsolutePreState = validCannonAbsolutPreState + config.CannonAbsolutePreState = validCannonAbsolutePreState config.CannonAbsolutePreStateBaseURL = nil require.NoError(t, config.Check()) }) @@ -143,14 +143,14 @@ func TestCannonRequiredArgs(t *testing.T) { t.Run(fmt.Sprintf("TestCannonAbsolutePreStateBaseURL-%v", traceType), func(t *testing.T) { config := validConfig(traceType) config.CannonAbsolutePreState = "" - config.CannonAbsolutePreStateBaseURL = validCannonAbsolutPreStateBaseURL + config.CannonAbsolutePreStateBaseURL = validCannonAbsolutePreStateBaseURL require.NoError(t, config.Check()) }) t.Run(fmt.Sprintf("TestMustNotSupplyBothCannonAbsolutePreStateAndBaseURL-%v", traceType), func(t *testing.T) { config := validConfig(traceType) - config.CannonAbsolutePreState = validCannonAbsolutPreState - config.CannonAbsolutePreStateBaseURL = validCannonAbsolutPreStateBaseURL + config.CannonAbsolutePreState = validCannonAbsolutePreState + config.CannonAbsolutePreStateBaseURL = validCannonAbsolutePreStateBaseURL require.ErrorIs(t, config.Check(), ErrCannonAbsolutePreStateAndBaseURL) }) @@ -241,7 +241,7 @@ func TestAsteriscRequiredArgs(t *testing.T) { t.Run(fmt.Sprintf("TestAsteriscAbsolutePreState-%v", traceType), func(t *testing.T) { config := validConfig(traceType) - config.AsteriscAbsolutePreState = validAsteriscAbsolutPreState + config.AsteriscAbsolutePreState = validAsteriscAbsolutePreState config.AsteriscAbsolutePreStateBaseURL = nil require.NoError(t, config.Check()) }) @@ -249,14 +249,14 @@ func TestAsteriscRequiredArgs(t *testing.T) { t.Run(fmt.Sprintf("TestAsteriscAbsolutePreStateBaseURL-%v", traceType), func(t *testing.T) { config := validConfig(traceType) config.AsteriscAbsolutePreState = "" - config.AsteriscAbsolutePreStateBaseURL = validAsteriscAbsolutPreStateBaseURL + config.AsteriscAbsolutePreStateBaseURL = validAsteriscAbsolutePreStateBaseURL require.NoError(t, config.Check()) }) t.Run(fmt.Sprintf("TestMustNotSupplyBothAsteriscAbsolutePreStateAndBaseURL-%v", traceType), func(t *testing.T) { config := validConfig(traceType) - config.AsteriscAbsolutePreState = validAsteriscAbsolutPreState - config.AsteriscAbsolutePreStateBaseURL = validAsteriscAbsolutPreStateBaseURL + config.AsteriscAbsolutePreState = validAsteriscAbsolutePreState + config.AsteriscAbsolutePreStateBaseURL = validAsteriscAbsolutePreStateBaseURL require.ErrorIs(t, config.Check(), ErrAsteriscAbsolutePreStateAndBaseURL) }) @@ -370,7 +370,7 @@ func TestRequireConfigForMultipleTraceTypesForCannon(t *testing.T) { cfg.CannonAbsolutePreState = "" cfg.CannonAbsolutePreStateBaseURL = nil require.ErrorIs(t, cfg.Check(), ErrMissingCannonAbsolutePreState) - cfg.CannonAbsolutePreState = validCannonAbsolutPreState + cfg.CannonAbsolutePreState = validCannonAbsolutePreState // Require output cannon specific args cfg.RollupRpc = "" @@ -388,7 +388,7 @@ func TestRequireConfigForMultipleTraceTypesForAsterisc(t *testing.T) { cfg.AsteriscAbsolutePreState = "" cfg.AsteriscAbsolutePreStateBaseURL = nil require.ErrorIs(t, cfg.Check(), ErrMissingAsteriscAbsolutePreState) - cfg.AsteriscAbsolutePreState = validAsteriscAbsolutPreState + cfg.AsteriscAbsolutePreState = validAsteriscAbsolutePreState // Require output asterisc specific args cfg.RollupRpc = "" @@ -413,7 +413,7 @@ func TestRequireConfigForMultipleTraceTypesForCannonAndAsterisc(t *testing.T) { cfg.AsteriscAbsolutePreState = "" cfg.AsteriscAbsolutePreStateBaseURL = nil require.ErrorIs(t, cfg.Check(), ErrMissingAsteriscAbsolutePreState) - cfg.AsteriscAbsolutePreState = validAsteriscAbsolutPreState + cfg.AsteriscAbsolutePreState = validAsteriscAbsolutePreState // Require cannon specific args cfg.Asterisc.Server = "" diff --git a/op-challenger/game/keccak/scheduler.go b/op-challenger/game/keccak/scheduler.go index e9d8cb583be48..233c2d218d31e 100644 --- a/op-challenger/game/keccak/scheduler.go +++ b/op-challenger/game/keccak/scheduler.go @@ -21,8 +21,13 @@ type OracleSource interface { Oracles() []keccakTypes.LargePreimageOracle } +type Metrics interface { + RecordLargePreimageCount(count int) +} + type LargePreimageScheduler struct { log log.Logger + m Metrics cl faultTypes.ClockReader ch chan common.Hash oracles OracleSource @@ -33,11 +38,13 @@ type LargePreimageScheduler struct { func NewLargePreimageScheduler( logger log.Logger, + m Metrics, cl faultTypes.ClockReader, oracleSource OracleSource, challenger Challenger) *LargePreimageScheduler { return &LargePreimageScheduler{ log: logger, + m: m, cl: cl, ch: make(chan common.Hash, 1), oracles: oracleSource, @@ -94,6 +101,7 @@ func (s *LargePreimageScheduler) verifyOraclePreimages(ctx context.Context, orac if err != nil { return err } + s.m.RecordLargePreimageCount(len(preimages)) period, err := oracle.ChallengePeriod(ctx) if err != nil { return fmt.Errorf("failed to load challenge period: %w", err) diff --git a/op-challenger/game/keccak/scheduler_test.go b/op-challenger/game/keccak/scheduler_test.go index 067fc5d93065f..30070becb82b7 100644 --- a/op-challenger/game/keccak/scheduler_test.go +++ b/op-challenger/game/keccak/scheduler_test.go @@ -9,6 +9,7 @@ import ( "time" keccakTypes "github.com/ethereum-optimism/optimism/op-challenger/game/keccak/types" + "github.com/ethereum-optimism/optimism/op-challenger/metrics" "github.com/ethereum-optimism/optimism/op-service/clock" "github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock" "github.com/ethereum-optimism/optimism/op-service/testlog" @@ -50,7 +51,7 @@ func TestScheduleNextCheck(t *testing.T) { } cl := clock.NewDeterministicClock(time.Unix(int64(currentTimestamp), 0)) challenger := &stubChallenger{} - scheduler := NewLargePreimageScheduler(logger, cl, OracleSourceArray{oracle}, challenger) + scheduler := NewLargePreimageScheduler(logger, metrics.NoopMetrics, cl, OracleSourceArray{oracle}, challenger) scheduler.Start(ctx) defer scheduler.Close() err := scheduler.Schedule(common.Hash{0xaa}, 3) diff --git a/op-challenger/game/service.go b/op-challenger/game/service.go index fea6bc2aaf63c..3aa0679d38c0f 100644 --- a/op-challenger/game/service.go +++ b/op-challenger/game/service.go @@ -246,7 +246,7 @@ func (s *Service) initLargePreimages() error { fetcher := fetcher.NewPreimageFetcher(s.logger, s.l1Client) verifier := keccak.NewPreimageVerifier(s.logger, fetcher) challenger := keccak.NewPreimageChallenger(s.logger, s.metrics, verifier, s.txSender) - s.preimages = keccak.NewLargePreimageScheduler(s.logger, s.l1Clock, s.oracles, challenger) + s.preimages = keccak.NewLargePreimageScheduler(s.logger, s.metrics, s.l1Clock, s.oracles, challenger) return nil } diff --git a/op-challenger/metrics/metrics.go b/op-challenger/metrics/metrics.go index c46edcd67fccd..b5c9d19e298f8 100644 --- a/op-challenger/metrics/metrics.go +++ b/op-challenger/metrics/metrics.go @@ -53,6 +53,8 @@ type Metricer interface { RecordGameUpdateScheduled() RecordGameUpdateCompleted() + RecordLargePreimageCount(count int) + IncActiveExecutors() DecActiveExecutors() IncIdleExecutors() @@ -81,6 +83,7 @@ type Metrics struct { preimageChallenged prometheus.Counter preimageChallengeFailed prometheus.Counter + preimageCount prometheus.Gauge highestActedL1Block prometheus.Gauge @@ -193,6 +196,11 @@ func NewMetrics() *Metrics { Name: "preimage_challenge_failed", Help: "Number of preimage challenges that failed", }), + preimageCount: factory.NewGauge(prometheus.GaugeOpts{ + Namespace: Namespace, + Name: "preimage_count", + Help: "Number of large preimage proposals being tracked by the challenger", + }), trackedGames: *factory.NewGaugeVec(prometheus.GaugeOpts{ Namespace: Namespace, Name: "tracked_games", @@ -261,6 +269,10 @@ func (m *Metrics) RecordPreimageChallengeFailed() { m.preimageChallengeFailed.Add(1) } +func (m *Metrics) RecordLargePreimageCount(count int) { + m.preimageCount.Set(float64(count)) +} + func (m *Metrics) RecordBondClaimFailed() { m.bondClaimFailures.Add(1) } diff --git a/op-challenger/metrics/noop.go b/op-challenger/metrics/noop.go index fc0f6d077803b..1a3faf00b2131 100644 --- a/op-challenger/metrics/noop.go +++ b/op-challenger/metrics/noop.go @@ -34,6 +34,7 @@ func (*NoopMetricsImpl) RecordActedL1Block(_ uint64) {} func (*NoopMetricsImpl) RecordPreimageChallenged() {} func (*NoopMetricsImpl) RecordPreimageChallengeFailed() {} +func (*NoopMetricsImpl) RecordLargePreimageCount(_ int) {} func (*NoopMetricsImpl) RecordBondClaimFailed() {} func (*NoopMetricsImpl) RecordBondClaimed(uint64) {} diff --git a/op-dispute-mon/bindings/faultdisputegame.go b/op-dispute-mon/bindings/faultdisputegame.go deleted file mode 100644 index d43287d3da6af..0000000000000 --- a/op-dispute-mon/bindings/faultdisputegame.go +++ /dev/null @@ -1,1877 +0,0 @@ -// 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 -) - -// FaultDisputeGameMetaData contains all meta data concerning the FaultDisputeGame contract. -var FaultDisputeGameMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"GameType\",\"name\":\"_gameType\",\"type\":\"uint32\"},{\"internalType\":\"Claim\",\"name\":\"_absolutePrestate\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"_maxGameDepth\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_splitDepth\",\"type\":\"uint256\"},{\"internalType\":\"Duration\",\"name\":\"_clockExtension\",\"type\":\"uint64\"},{\"internalType\":\"Duration\",\"name\":\"_maxClockDuration\",\"type\":\"uint64\"},{\"internalType\":\"contractIBigStepper\",\"name\":\"_vm\",\"type\":\"address\"},{\"internalType\":\"contractIDelayedWETH\",\"name\":\"_weth\",\"type\":\"address\"},{\"internalType\":\"contractIAnchorStateRegistry\",\"name\":\"_anchorStateRegistry\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_l2ChainId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"absolutePrestate\",\"outputs\":[{\"internalType\":\"Claim\",\"name\":\"absolutePrestate_\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_ident\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_execLeafIdx\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_partOffset\",\"type\":\"uint256\"}],\"name\":\"addLocalData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"anchorStateRegistry\",\"outputs\":[{\"internalType\":\"contractIAnchorStateRegistry\",\"name\":\"registry_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"Claim\",\"name\":\"_disputed\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"_parentIndex\",\"type\":\"uint256\"},{\"internalType\":\"Claim\",\"name\":\"_claim\",\"type\":\"bytes32\"}],\"name\":\"attack\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"version\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"messagePasserStorageRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"latestBlockhash\",\"type\":\"bytes32\"}],\"internalType\":\"structTypes.OutputRootProof\",\"name\":\"_outputRootProof\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"_headerRLP\",\"type\":\"bytes\"}],\"name\":\"challengeRootL2Block\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"}],\"name\":\"claimCredit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"claimData\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"parentIndex\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"counteredBy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"claimant\",\"type\":\"address\"},{\"internalType\":\"uint128\",\"name\":\"bond\",\"type\":\"uint128\"},{\"internalType\":\"Claim\",\"name\":\"claim\",\"type\":\"bytes32\"},{\"internalType\":\"Position\",\"name\":\"position\",\"type\":\"uint128\"},{\"internalType\":\"Clock\",\"name\":\"clock\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimDataLen\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"len_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"Hash\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"claims\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"clockExtension\",\"outputs\":[{\"internalType\":\"Duration\",\"name\":\"clockExtension_\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createdAt\",\"outputs\":[{\"internalType\":\"Timestamp\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"credit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"Claim\",\"name\":\"_disputed\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"_parentIndex\",\"type\":\"uint256\"},{\"internalType\":\"Claim\",\"name\":\"_claim\",\"type\":\"bytes32\"}],\"name\":\"defend\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"extraData\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"extraData_\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gameCreator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"creator_\",\"type\":\"address\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gameData\",\"outputs\":[{\"internalType\":\"GameType\",\"name\":\"gameType_\",\"type\":\"uint32\"},{\"internalType\":\"Claim\",\"name\":\"rootClaim_\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"extraData_\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gameType\",\"outputs\":[{\"internalType\":\"GameType\",\"name\":\"gameType_\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_claimIndex\",\"type\":\"uint256\"}],\"name\":\"getChallengerDuration\",\"outputs\":[{\"internalType\":\"Duration\",\"name\":\"duration_\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_claimIndex\",\"type\":\"uint256\"}],\"name\":\"getNumToResolve\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"numRemainingChildren_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"Position\",\"name\":\"_position\",\"type\":\"uint128\"}],\"name\":\"getRequiredBond\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requiredBond_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1Head\",\"outputs\":[{\"internalType\":\"Hash\",\"name\":\"l1Head_\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2BlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"l2BlockNumber_\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2BlockNumberChallenged\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2BlockNumberChallenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2ChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"l2ChainId_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxClockDuration\",\"outputs\":[{\"internalType\":\"Duration\",\"name\":\"maxClockDuration_\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxGameDepth\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"maxGameDepth_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"Claim\",\"name\":\"_disputed\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"_challengeIndex\",\"type\":\"uint256\"},{\"internalType\":\"Claim\",\"name\":\"_claim\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"_isAttack\",\"type\":\"bool\"}],\"name\":\"move\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"resolutionCheckpoints\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"initialCheckpointComplete\",\"type\":\"bool\"},{\"internalType\":\"uint32\",\"name\":\"subgameIndex\",\"type\":\"uint32\"},{\"internalType\":\"Position\",\"name\":\"leftmostPosition\",\"type\":\"uint128\"},{\"internalType\":\"address\",\"name\":\"counteredBy\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"resolve\",\"outputs\":[{\"internalType\":\"enumGameStatus\",\"name\":\"status_\",\"type\":\"uint8\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_claimIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_numToResolve\",\"type\":\"uint256\"}],\"name\":\"resolveClaim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"resolvedAt\",\"outputs\":[{\"internalType\":\"Timestamp\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"resolvedSubgames\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rootClaim\",\"outputs\":[{\"internalType\":\"Claim\",\"name\":\"rootClaim_\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"splitDepth\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"splitDepth_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"startingBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"startingBlockNumber_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"startingOutputRoot\",\"outputs\":[{\"internalType\":\"Hash\",\"name\":\"root\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"l2BlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"startingRootHash\",\"outputs\":[{\"internalType\":\"Hash\",\"name\":\"startingRootHash_\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"status\",\"outputs\":[{\"internalType\":\"enumGameStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_claimIndex\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_isAttack\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"_stateData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_proof\",\"type\":\"bytes\"}],\"name\":\"step\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"subgames\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vm\",\"outputs\":[{\"internalType\":\"contractIBigStepper\",\"name\":\"vm_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"weth\",\"outputs\":[{\"internalType\":\"contractIDelayedWETH\",\"name\":\"weth_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"parentIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"Claim\",\"name\":\"claim\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"claimant\",\"type\":\"address\"}],\"name\":\"Move\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"enumGameStatus\",\"name\":\"status\",\"type\":\"uint8\"}],\"name\":\"Resolved\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"AlreadyInitialized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AnchorRootNotFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BlockNumberMatches\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BondTransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotDefendRootClaim\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ClaimAboveSplit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ClaimAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ClaimAlreadyResolved\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ClockNotExpired\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ClockTimeExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ContentLengthMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateStep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyItem\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GameDepthExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GameNotInProgress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectBondAmount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidClockExtension\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataRemainder\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDisputedClaimIndex\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidHeader\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidHeaderRLP\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidLocalIdent\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidOutputRootProof\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidParent\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPrestate\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSplitDepth\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"L2BlockNumberChallenged\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxDepthTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoCreditToClaim\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OutOfOrderResolution\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnexpectedList\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"Claim\",\"name\":\"rootClaim\",\"type\":\"bytes32\"}],\"name\":\"UnexpectedRootClaim\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnexpectedString\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValidStep\",\"type\":\"error\"}]", -} - -// FaultDisputeGameABI is the input ABI used to generate the binding from. -// Deprecated: Use FaultDisputeGameMetaData.ABI instead. -var FaultDisputeGameABI = FaultDisputeGameMetaData.ABI - -// FaultDisputeGame is an auto generated Go binding around an Ethereum contract. -type FaultDisputeGame struct { - FaultDisputeGameCaller // Read-only binding to the contract - FaultDisputeGameTransactor // Write-only binding to the contract - FaultDisputeGameFilterer // Log filterer for contract events -} - -// FaultDisputeGameCaller is an auto generated read-only Go binding around an Ethereum contract. -type FaultDisputeGameCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// FaultDisputeGameTransactor is an auto generated write-only Go binding around an Ethereum contract. -type FaultDisputeGameTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// FaultDisputeGameFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type FaultDisputeGameFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// FaultDisputeGameSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type FaultDisputeGameSession struct { - Contract *FaultDisputeGame // 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 -} - -// FaultDisputeGameCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type FaultDisputeGameCallerSession struct { - Contract *FaultDisputeGameCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// FaultDisputeGameTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type FaultDisputeGameTransactorSession struct { - Contract *FaultDisputeGameTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// FaultDisputeGameRaw is an auto generated low-level Go binding around an Ethereum contract. -type FaultDisputeGameRaw struct { - Contract *FaultDisputeGame // Generic contract binding to access the raw methods on -} - -// FaultDisputeGameCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type FaultDisputeGameCallerRaw struct { - Contract *FaultDisputeGameCaller // Generic read-only contract binding to access the raw methods on -} - -// FaultDisputeGameTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type FaultDisputeGameTransactorRaw struct { - Contract *FaultDisputeGameTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewFaultDisputeGame creates a new instance of FaultDisputeGame, bound to a specific deployed contract. -func NewFaultDisputeGame(address common.Address, backend bind.ContractBackend) (*FaultDisputeGame, error) { - contract, err := bindFaultDisputeGame(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &FaultDisputeGame{FaultDisputeGameCaller: FaultDisputeGameCaller{contract: contract}, FaultDisputeGameTransactor: FaultDisputeGameTransactor{contract: contract}, FaultDisputeGameFilterer: FaultDisputeGameFilterer{contract: contract}}, nil -} - -// NewFaultDisputeGameCaller creates a new read-only instance of FaultDisputeGame, bound to a specific deployed contract. -func NewFaultDisputeGameCaller(address common.Address, caller bind.ContractCaller) (*FaultDisputeGameCaller, error) { - contract, err := bindFaultDisputeGame(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &FaultDisputeGameCaller{contract: contract}, nil -} - -// NewFaultDisputeGameTransactor creates a new write-only instance of FaultDisputeGame, bound to a specific deployed contract. -func NewFaultDisputeGameTransactor(address common.Address, transactor bind.ContractTransactor) (*FaultDisputeGameTransactor, error) { - contract, err := bindFaultDisputeGame(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &FaultDisputeGameTransactor{contract: contract}, nil -} - -// NewFaultDisputeGameFilterer creates a new log filterer instance of FaultDisputeGame, bound to a specific deployed contract. -func NewFaultDisputeGameFilterer(address common.Address, filterer bind.ContractFilterer) (*FaultDisputeGameFilterer, error) { - contract, err := bindFaultDisputeGame(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &FaultDisputeGameFilterer{contract: contract}, nil -} - -// bindFaultDisputeGame binds a generic wrapper to an already deployed contract. -func bindFaultDisputeGame(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(FaultDisputeGameABI)) - 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 (_FaultDisputeGame *FaultDisputeGameRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _FaultDisputeGame.Contract.FaultDisputeGameCaller.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 (_FaultDisputeGame *FaultDisputeGameRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _FaultDisputeGame.Contract.FaultDisputeGameTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_FaultDisputeGame *FaultDisputeGameRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _FaultDisputeGame.Contract.FaultDisputeGameTransactor.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 (_FaultDisputeGame *FaultDisputeGameCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _FaultDisputeGame.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 (_FaultDisputeGame *FaultDisputeGameTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _FaultDisputeGame.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_FaultDisputeGame *FaultDisputeGameTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _FaultDisputeGame.Contract.contract.Transact(opts, method, params...) -} - -// AbsolutePrestate is a free data retrieval call binding the contract method 0x8d450a95. -// -// Solidity: function absolutePrestate() view returns(bytes32 absolutePrestate_) -func (_FaultDisputeGame *FaultDisputeGameCaller) AbsolutePrestate(opts *bind.CallOpts) ([32]byte, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "absolutePrestate") - - if err != nil { - return *new([32]byte), err - } - - out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) - - return out0, err - -} - -// AbsolutePrestate is a free data retrieval call binding the contract method 0x8d450a95. -// -// Solidity: function absolutePrestate() view returns(bytes32 absolutePrestate_) -func (_FaultDisputeGame *FaultDisputeGameSession) AbsolutePrestate() ([32]byte, error) { - return _FaultDisputeGame.Contract.AbsolutePrestate(&_FaultDisputeGame.CallOpts) -} - -// AbsolutePrestate is a free data retrieval call binding the contract method 0x8d450a95. -// -// Solidity: function absolutePrestate() view returns(bytes32 absolutePrestate_) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) AbsolutePrestate() ([32]byte, error) { - return _FaultDisputeGame.Contract.AbsolutePrestate(&_FaultDisputeGame.CallOpts) -} - -// AnchorStateRegistry is a free data retrieval call binding the contract method 0x5c0cba33. -// -// Solidity: function anchorStateRegistry() view returns(address registry_) -func (_FaultDisputeGame *FaultDisputeGameCaller) AnchorStateRegistry(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "anchorStateRegistry") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// AnchorStateRegistry is a free data retrieval call binding the contract method 0x5c0cba33. -// -// Solidity: function anchorStateRegistry() view returns(address registry_) -func (_FaultDisputeGame *FaultDisputeGameSession) AnchorStateRegistry() (common.Address, error) { - return _FaultDisputeGame.Contract.AnchorStateRegistry(&_FaultDisputeGame.CallOpts) -} - -// AnchorStateRegistry is a free data retrieval call binding the contract method 0x5c0cba33. -// -// Solidity: function anchorStateRegistry() view returns(address registry_) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) AnchorStateRegistry() (common.Address, error) { - return _FaultDisputeGame.Contract.AnchorStateRegistry(&_FaultDisputeGame.CallOpts) -} - -// ClaimData is a free data retrieval call binding the contract method 0xc6f0308c. -// -// Solidity: function claimData(uint256 ) view returns(uint32 parentIndex, address counteredBy, address claimant, uint128 bond, bytes32 claim, uint128 position, uint128 clock) -func (_FaultDisputeGame *FaultDisputeGameCaller) ClaimData(opts *bind.CallOpts, arg0 *big.Int) (struct { - ParentIndex uint32 - CounteredBy common.Address - Claimant common.Address - Bond *big.Int - Claim [32]byte - Position *big.Int - Clock *big.Int -}, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "claimData", arg0) - - outstruct := new(struct { - ParentIndex uint32 - CounteredBy common.Address - Claimant common.Address - Bond *big.Int - Claim [32]byte - Position *big.Int - Clock *big.Int - }) - if err != nil { - return *outstruct, err - } - - outstruct.ParentIndex = *abi.ConvertType(out[0], new(uint32)).(*uint32) - outstruct.CounteredBy = *abi.ConvertType(out[1], new(common.Address)).(*common.Address) - outstruct.Claimant = *abi.ConvertType(out[2], new(common.Address)).(*common.Address) - outstruct.Bond = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) - outstruct.Claim = *abi.ConvertType(out[4], new([32]byte)).(*[32]byte) - outstruct.Position = *abi.ConvertType(out[5], new(*big.Int)).(**big.Int) - outstruct.Clock = *abi.ConvertType(out[6], new(*big.Int)).(**big.Int) - - return *outstruct, err - -} - -// ClaimData is a free data retrieval call binding the contract method 0xc6f0308c. -// -// Solidity: function claimData(uint256 ) view returns(uint32 parentIndex, address counteredBy, address claimant, uint128 bond, bytes32 claim, uint128 position, uint128 clock) -func (_FaultDisputeGame *FaultDisputeGameSession) ClaimData(arg0 *big.Int) (struct { - ParentIndex uint32 - CounteredBy common.Address - Claimant common.Address - Bond *big.Int - Claim [32]byte - Position *big.Int - Clock *big.Int -}, error) { - return _FaultDisputeGame.Contract.ClaimData(&_FaultDisputeGame.CallOpts, arg0) -} - -// ClaimData is a free data retrieval call binding the contract method 0xc6f0308c. -// -// Solidity: function claimData(uint256 ) view returns(uint32 parentIndex, address counteredBy, address claimant, uint128 bond, bytes32 claim, uint128 position, uint128 clock) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) ClaimData(arg0 *big.Int) (struct { - ParentIndex uint32 - CounteredBy common.Address - Claimant common.Address - Bond *big.Int - Claim [32]byte - Position *big.Int - Clock *big.Int -}, error) { - return _FaultDisputeGame.Contract.ClaimData(&_FaultDisputeGame.CallOpts, arg0) -} - -// ClaimDataLen is a free data retrieval call binding the contract method 0x8980e0cc. -// -// Solidity: function claimDataLen() view returns(uint256 len_) -func (_FaultDisputeGame *FaultDisputeGameCaller) ClaimDataLen(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "claimDataLen") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// ClaimDataLen is a free data retrieval call binding the contract method 0x8980e0cc. -// -// Solidity: function claimDataLen() view returns(uint256 len_) -func (_FaultDisputeGame *FaultDisputeGameSession) ClaimDataLen() (*big.Int, error) { - return _FaultDisputeGame.Contract.ClaimDataLen(&_FaultDisputeGame.CallOpts) -} - -// ClaimDataLen is a free data retrieval call binding the contract method 0x8980e0cc. -// -// Solidity: function claimDataLen() view returns(uint256 len_) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) ClaimDataLen() (*big.Int, error) { - return _FaultDisputeGame.Contract.ClaimDataLen(&_FaultDisputeGame.CallOpts) -} - -// Claims is a free data retrieval call binding the contract method 0xeff0f592. -// -// Solidity: function claims(bytes32 ) view returns(bool) -func (_FaultDisputeGame *FaultDisputeGameCaller) Claims(opts *bind.CallOpts, arg0 [32]byte) (bool, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "claims", arg0) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// Claims is a free data retrieval call binding the contract method 0xeff0f592. -// -// Solidity: function claims(bytes32 ) view returns(bool) -func (_FaultDisputeGame *FaultDisputeGameSession) Claims(arg0 [32]byte) (bool, error) { - return _FaultDisputeGame.Contract.Claims(&_FaultDisputeGame.CallOpts, arg0) -} - -// Claims is a free data retrieval call binding the contract method 0xeff0f592. -// -// Solidity: function claims(bytes32 ) view returns(bool) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) Claims(arg0 [32]byte) (bool, error) { - return _FaultDisputeGame.Contract.Claims(&_FaultDisputeGame.CallOpts, arg0) -} - -// ClockExtension is a free data retrieval call binding the contract method 0x6b6716c0. -// -// Solidity: function clockExtension() view returns(uint64 clockExtension_) -func (_FaultDisputeGame *FaultDisputeGameCaller) ClockExtension(opts *bind.CallOpts) (uint64, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "clockExtension") - - if err != nil { - return *new(uint64), err - } - - out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) - - return out0, err - -} - -// ClockExtension is a free data retrieval call binding the contract method 0x6b6716c0. -// -// Solidity: function clockExtension() view returns(uint64 clockExtension_) -func (_FaultDisputeGame *FaultDisputeGameSession) ClockExtension() (uint64, error) { - return _FaultDisputeGame.Contract.ClockExtension(&_FaultDisputeGame.CallOpts) -} - -// ClockExtension is a free data retrieval call binding the contract method 0x6b6716c0. -// -// Solidity: function clockExtension() view returns(uint64 clockExtension_) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) ClockExtension() (uint64, error) { - return _FaultDisputeGame.Contract.ClockExtension(&_FaultDisputeGame.CallOpts) -} - -// CreatedAt is a free data retrieval call binding the contract method 0xcf09e0d0. -// -// Solidity: function createdAt() view returns(uint64) -func (_FaultDisputeGame *FaultDisputeGameCaller) CreatedAt(opts *bind.CallOpts) (uint64, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "createdAt") - - if err != nil { - return *new(uint64), err - } - - out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) - - return out0, err - -} - -// CreatedAt is a free data retrieval call binding the contract method 0xcf09e0d0. -// -// Solidity: function createdAt() view returns(uint64) -func (_FaultDisputeGame *FaultDisputeGameSession) CreatedAt() (uint64, error) { - return _FaultDisputeGame.Contract.CreatedAt(&_FaultDisputeGame.CallOpts) -} - -// CreatedAt is a free data retrieval call binding the contract method 0xcf09e0d0. -// -// Solidity: function createdAt() view returns(uint64) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) CreatedAt() (uint64, error) { - return _FaultDisputeGame.Contract.CreatedAt(&_FaultDisputeGame.CallOpts) -} - -// Credit is a free data retrieval call binding the contract method 0xd5d44d80. -// -// Solidity: function credit(address ) view returns(uint256) -func (_FaultDisputeGame *FaultDisputeGameCaller) Credit(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "credit", arg0) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// Credit is a free data retrieval call binding the contract method 0xd5d44d80. -// -// Solidity: function credit(address ) view returns(uint256) -func (_FaultDisputeGame *FaultDisputeGameSession) Credit(arg0 common.Address) (*big.Int, error) { - return _FaultDisputeGame.Contract.Credit(&_FaultDisputeGame.CallOpts, arg0) -} - -// Credit is a free data retrieval call binding the contract method 0xd5d44d80. -// -// Solidity: function credit(address ) view returns(uint256) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) Credit(arg0 common.Address) (*big.Int, error) { - return _FaultDisputeGame.Contract.Credit(&_FaultDisputeGame.CallOpts, arg0) -} - -// ExtraData is a free data retrieval call binding the contract method 0x609d3334. -// -// Solidity: function extraData() pure returns(bytes extraData_) -func (_FaultDisputeGame *FaultDisputeGameCaller) ExtraData(opts *bind.CallOpts) ([]byte, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "extraData") - - if err != nil { - return *new([]byte), err - } - - out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) - - return out0, err - -} - -// ExtraData is a free data retrieval call binding the contract method 0x609d3334. -// -// Solidity: function extraData() pure returns(bytes extraData_) -func (_FaultDisputeGame *FaultDisputeGameSession) ExtraData() ([]byte, error) { - return _FaultDisputeGame.Contract.ExtraData(&_FaultDisputeGame.CallOpts) -} - -// ExtraData is a free data retrieval call binding the contract method 0x609d3334. -// -// Solidity: function extraData() pure returns(bytes extraData_) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) ExtraData() ([]byte, error) { - return _FaultDisputeGame.Contract.ExtraData(&_FaultDisputeGame.CallOpts) -} - -// GameCreator is a free data retrieval call binding the contract method 0x37b1b229. -// -// Solidity: function gameCreator() pure returns(address creator_) -func (_FaultDisputeGame *FaultDisputeGameCaller) GameCreator(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "gameCreator") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// GameCreator is a free data retrieval call binding the contract method 0x37b1b229. -// -// Solidity: function gameCreator() pure returns(address creator_) -func (_FaultDisputeGame *FaultDisputeGameSession) GameCreator() (common.Address, error) { - return _FaultDisputeGame.Contract.GameCreator(&_FaultDisputeGame.CallOpts) -} - -// GameCreator is a free data retrieval call binding the contract method 0x37b1b229. -// -// Solidity: function gameCreator() pure returns(address creator_) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) GameCreator() (common.Address, error) { - return _FaultDisputeGame.Contract.GameCreator(&_FaultDisputeGame.CallOpts) -} - -// GameData is a free data retrieval call binding the contract method 0xfa24f743. -// -// Solidity: function gameData() view returns(uint32 gameType_, bytes32 rootClaim_, bytes extraData_) -func (_FaultDisputeGame *FaultDisputeGameCaller) GameData(opts *bind.CallOpts) (struct { - GameType uint32 - RootClaim [32]byte - ExtraData []byte -}, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "gameData") - - outstruct := new(struct { - GameType uint32 - RootClaim [32]byte - ExtraData []byte - }) - if err != nil { - return *outstruct, err - } - - outstruct.GameType = *abi.ConvertType(out[0], new(uint32)).(*uint32) - outstruct.RootClaim = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte) - outstruct.ExtraData = *abi.ConvertType(out[2], new([]byte)).(*[]byte) - - return *outstruct, err - -} - -// GameData is a free data retrieval call binding the contract method 0xfa24f743. -// -// Solidity: function gameData() view returns(uint32 gameType_, bytes32 rootClaim_, bytes extraData_) -func (_FaultDisputeGame *FaultDisputeGameSession) GameData() (struct { - GameType uint32 - RootClaim [32]byte - ExtraData []byte -}, error) { - return _FaultDisputeGame.Contract.GameData(&_FaultDisputeGame.CallOpts) -} - -// GameData is a free data retrieval call binding the contract method 0xfa24f743. -// -// Solidity: function gameData() view returns(uint32 gameType_, bytes32 rootClaim_, bytes extraData_) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) GameData() (struct { - GameType uint32 - RootClaim [32]byte - ExtraData []byte -}, error) { - return _FaultDisputeGame.Contract.GameData(&_FaultDisputeGame.CallOpts) -} - -// GameType is a free data retrieval call binding the contract method 0xbbdc02db. -// -// Solidity: function gameType() view returns(uint32 gameType_) -func (_FaultDisputeGame *FaultDisputeGameCaller) GameType(opts *bind.CallOpts) (uint32, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "gameType") - - if err != nil { - return *new(uint32), err - } - - out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32) - - return out0, err - -} - -// GameType is a free data retrieval call binding the contract method 0xbbdc02db. -// -// Solidity: function gameType() view returns(uint32 gameType_) -func (_FaultDisputeGame *FaultDisputeGameSession) GameType() (uint32, error) { - return _FaultDisputeGame.Contract.GameType(&_FaultDisputeGame.CallOpts) -} - -// GameType is a free data retrieval call binding the contract method 0xbbdc02db. -// -// Solidity: function gameType() view returns(uint32 gameType_) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) GameType() (uint32, error) { - return _FaultDisputeGame.Contract.GameType(&_FaultDisputeGame.CallOpts) -} - -// GetChallengerDuration is a free data retrieval call binding the contract method 0xbd8da956. -// -// Solidity: function getChallengerDuration(uint256 _claimIndex) view returns(uint64 duration_) -func (_FaultDisputeGame *FaultDisputeGameCaller) GetChallengerDuration(opts *bind.CallOpts, _claimIndex *big.Int) (uint64, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "getChallengerDuration", _claimIndex) - - if err != nil { - return *new(uint64), err - } - - out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) - - return out0, err - -} - -// GetChallengerDuration is a free data retrieval call binding the contract method 0xbd8da956. -// -// Solidity: function getChallengerDuration(uint256 _claimIndex) view returns(uint64 duration_) -func (_FaultDisputeGame *FaultDisputeGameSession) GetChallengerDuration(_claimIndex *big.Int) (uint64, error) { - return _FaultDisputeGame.Contract.GetChallengerDuration(&_FaultDisputeGame.CallOpts, _claimIndex) -} - -// GetChallengerDuration is a free data retrieval call binding the contract method 0xbd8da956. -// -// Solidity: function getChallengerDuration(uint256 _claimIndex) view returns(uint64 duration_) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) GetChallengerDuration(_claimIndex *big.Int) (uint64, error) { - return _FaultDisputeGame.Contract.GetChallengerDuration(&_FaultDisputeGame.CallOpts, _claimIndex) -} - -// GetNumToResolve is a free data retrieval call binding the contract method 0x5a5fa2d9. -// -// Solidity: function getNumToResolve(uint256 _claimIndex) view returns(uint256 numRemainingChildren_) -func (_FaultDisputeGame *FaultDisputeGameCaller) GetNumToResolve(opts *bind.CallOpts, _claimIndex *big.Int) (*big.Int, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "getNumToResolve", _claimIndex) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetNumToResolve is a free data retrieval call binding the contract method 0x5a5fa2d9. -// -// Solidity: function getNumToResolve(uint256 _claimIndex) view returns(uint256 numRemainingChildren_) -func (_FaultDisputeGame *FaultDisputeGameSession) GetNumToResolve(_claimIndex *big.Int) (*big.Int, error) { - return _FaultDisputeGame.Contract.GetNumToResolve(&_FaultDisputeGame.CallOpts, _claimIndex) -} - -// GetNumToResolve is a free data retrieval call binding the contract method 0x5a5fa2d9. -// -// Solidity: function getNumToResolve(uint256 _claimIndex) view returns(uint256 numRemainingChildren_) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) GetNumToResolve(_claimIndex *big.Int) (*big.Int, error) { - return _FaultDisputeGame.Contract.GetNumToResolve(&_FaultDisputeGame.CallOpts, _claimIndex) -} - -// GetRequiredBond is a free data retrieval call binding the contract method 0xc395e1ca. -// -// Solidity: function getRequiredBond(uint128 _position) view returns(uint256 requiredBond_) -func (_FaultDisputeGame *FaultDisputeGameCaller) GetRequiredBond(opts *bind.CallOpts, _position *big.Int) (*big.Int, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "getRequiredBond", _position) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetRequiredBond is a free data retrieval call binding the contract method 0xc395e1ca. -// -// Solidity: function getRequiredBond(uint128 _position) view returns(uint256 requiredBond_) -func (_FaultDisputeGame *FaultDisputeGameSession) GetRequiredBond(_position *big.Int) (*big.Int, error) { - return _FaultDisputeGame.Contract.GetRequiredBond(&_FaultDisputeGame.CallOpts, _position) -} - -// GetRequiredBond is a free data retrieval call binding the contract method 0xc395e1ca. -// -// Solidity: function getRequiredBond(uint128 _position) view returns(uint256 requiredBond_) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) GetRequiredBond(_position *big.Int) (*big.Int, error) { - return _FaultDisputeGame.Contract.GetRequiredBond(&_FaultDisputeGame.CallOpts, _position) -} - -// L1Head is a free data retrieval call binding the contract method 0x6361506d. -// -// Solidity: function l1Head() pure returns(bytes32 l1Head_) -func (_FaultDisputeGame *FaultDisputeGameCaller) L1Head(opts *bind.CallOpts) ([32]byte, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "l1Head") - - if err != nil { - return *new([32]byte), err - } - - out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) - - return out0, err - -} - -// L1Head is a free data retrieval call binding the contract method 0x6361506d. -// -// Solidity: function l1Head() pure returns(bytes32 l1Head_) -func (_FaultDisputeGame *FaultDisputeGameSession) L1Head() ([32]byte, error) { - return _FaultDisputeGame.Contract.L1Head(&_FaultDisputeGame.CallOpts) -} - -// L1Head is a free data retrieval call binding the contract method 0x6361506d. -// -// Solidity: function l1Head() pure returns(bytes32 l1Head_) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) L1Head() ([32]byte, error) { - return _FaultDisputeGame.Contract.L1Head(&_FaultDisputeGame.CallOpts) -} - -// L2BlockNumber is a free data retrieval call binding the contract method 0x8b85902b. -// -// Solidity: function l2BlockNumber() pure returns(uint256 l2BlockNumber_) -func (_FaultDisputeGame *FaultDisputeGameCaller) L2BlockNumber(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "l2BlockNumber") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// L2BlockNumber is a free data retrieval call binding the contract method 0x8b85902b. -// -// Solidity: function l2BlockNumber() pure returns(uint256 l2BlockNumber_) -func (_FaultDisputeGame *FaultDisputeGameSession) L2BlockNumber() (*big.Int, error) { - return _FaultDisputeGame.Contract.L2BlockNumber(&_FaultDisputeGame.CallOpts) -} - -// L2BlockNumber is a free data retrieval call binding the contract method 0x8b85902b. -// -// Solidity: function l2BlockNumber() pure returns(uint256 l2BlockNumber_) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) L2BlockNumber() (*big.Int, error) { - return _FaultDisputeGame.Contract.L2BlockNumber(&_FaultDisputeGame.CallOpts) -} - -// L2BlockNumberChallenged is a free data retrieval call binding the contract method 0x3e3ac912. -// -// Solidity: function l2BlockNumberChallenged() view returns(bool) -func (_FaultDisputeGame *FaultDisputeGameCaller) L2BlockNumberChallenged(opts *bind.CallOpts) (bool, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "l2BlockNumberChallenged") - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// L2BlockNumberChallenged is a free data retrieval call binding the contract method 0x3e3ac912. -// -// Solidity: function l2BlockNumberChallenged() view returns(bool) -func (_FaultDisputeGame *FaultDisputeGameSession) L2BlockNumberChallenged() (bool, error) { - return _FaultDisputeGame.Contract.L2BlockNumberChallenged(&_FaultDisputeGame.CallOpts) -} - -// L2BlockNumberChallenged is a free data retrieval call binding the contract method 0x3e3ac912. -// -// Solidity: function l2BlockNumberChallenged() view returns(bool) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) L2BlockNumberChallenged() (bool, error) { - return _FaultDisputeGame.Contract.L2BlockNumberChallenged(&_FaultDisputeGame.CallOpts) -} - -// L2BlockNumberChallenger is a free data retrieval call binding the contract method 0x30dbe570. -// -// Solidity: function l2BlockNumberChallenger() view returns(address) -func (_FaultDisputeGame *FaultDisputeGameCaller) L2BlockNumberChallenger(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "l2BlockNumberChallenger") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// L2BlockNumberChallenger is a free data retrieval call binding the contract method 0x30dbe570. -// -// Solidity: function l2BlockNumberChallenger() view returns(address) -func (_FaultDisputeGame *FaultDisputeGameSession) L2BlockNumberChallenger() (common.Address, error) { - return _FaultDisputeGame.Contract.L2BlockNumberChallenger(&_FaultDisputeGame.CallOpts) -} - -// L2BlockNumberChallenger is a free data retrieval call binding the contract method 0x30dbe570. -// -// Solidity: function l2BlockNumberChallenger() view returns(address) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) L2BlockNumberChallenger() (common.Address, error) { - return _FaultDisputeGame.Contract.L2BlockNumberChallenger(&_FaultDisputeGame.CallOpts) -} - -// L2ChainId is a free data retrieval call binding the contract method 0xd6ae3cd5. -// -// Solidity: function l2ChainId() view returns(uint256 l2ChainId_) -func (_FaultDisputeGame *FaultDisputeGameCaller) L2ChainId(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "l2ChainId") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// L2ChainId is a free data retrieval call binding the contract method 0xd6ae3cd5. -// -// Solidity: function l2ChainId() view returns(uint256 l2ChainId_) -func (_FaultDisputeGame *FaultDisputeGameSession) L2ChainId() (*big.Int, error) { - return _FaultDisputeGame.Contract.L2ChainId(&_FaultDisputeGame.CallOpts) -} - -// L2ChainId is a free data retrieval call binding the contract method 0xd6ae3cd5. -// -// Solidity: function l2ChainId() view returns(uint256 l2ChainId_) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) L2ChainId() (*big.Int, error) { - return _FaultDisputeGame.Contract.L2ChainId(&_FaultDisputeGame.CallOpts) -} - -// MaxClockDuration is a free data retrieval call binding the contract method 0xdabd396d. -// -// Solidity: function maxClockDuration() view returns(uint64 maxClockDuration_) -func (_FaultDisputeGame *FaultDisputeGameCaller) MaxClockDuration(opts *bind.CallOpts) (uint64, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "maxClockDuration") - - if err != nil { - return *new(uint64), err - } - - out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) - - return out0, err - -} - -// MaxClockDuration is a free data retrieval call binding the contract method 0xdabd396d. -// -// Solidity: function maxClockDuration() view returns(uint64 maxClockDuration_) -func (_FaultDisputeGame *FaultDisputeGameSession) MaxClockDuration() (uint64, error) { - return _FaultDisputeGame.Contract.MaxClockDuration(&_FaultDisputeGame.CallOpts) -} - -// MaxClockDuration is a free data retrieval call binding the contract method 0xdabd396d. -// -// Solidity: function maxClockDuration() view returns(uint64 maxClockDuration_) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) MaxClockDuration() (uint64, error) { - return _FaultDisputeGame.Contract.MaxClockDuration(&_FaultDisputeGame.CallOpts) -} - -// MaxGameDepth is a free data retrieval call binding the contract method 0xfa315aa9. -// -// Solidity: function maxGameDepth() view returns(uint256 maxGameDepth_) -func (_FaultDisputeGame *FaultDisputeGameCaller) MaxGameDepth(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "maxGameDepth") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// MaxGameDepth is a free data retrieval call binding the contract method 0xfa315aa9. -// -// Solidity: function maxGameDepth() view returns(uint256 maxGameDepth_) -func (_FaultDisputeGame *FaultDisputeGameSession) MaxGameDepth() (*big.Int, error) { - return _FaultDisputeGame.Contract.MaxGameDepth(&_FaultDisputeGame.CallOpts) -} - -// MaxGameDepth is a free data retrieval call binding the contract method 0xfa315aa9. -// -// Solidity: function maxGameDepth() view returns(uint256 maxGameDepth_) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) MaxGameDepth() (*big.Int, error) { - return _FaultDisputeGame.Contract.MaxGameDepth(&_FaultDisputeGame.CallOpts) -} - -// ResolutionCheckpoints is a free data retrieval call binding the contract method 0xa445ece6. -// -// Solidity: function resolutionCheckpoints(uint256 ) view returns(bool initialCheckpointComplete, uint32 subgameIndex, uint128 leftmostPosition, address counteredBy) -func (_FaultDisputeGame *FaultDisputeGameCaller) ResolutionCheckpoints(opts *bind.CallOpts, arg0 *big.Int) (struct { - InitialCheckpointComplete bool - SubgameIndex uint32 - LeftmostPosition *big.Int - CounteredBy common.Address -}, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "resolutionCheckpoints", arg0) - - outstruct := new(struct { - InitialCheckpointComplete bool - SubgameIndex uint32 - LeftmostPosition *big.Int - CounteredBy common.Address - }) - if err != nil { - return *outstruct, err - } - - outstruct.InitialCheckpointComplete = *abi.ConvertType(out[0], new(bool)).(*bool) - outstruct.SubgameIndex = *abi.ConvertType(out[1], new(uint32)).(*uint32) - outstruct.LeftmostPosition = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) - outstruct.CounteredBy = *abi.ConvertType(out[3], new(common.Address)).(*common.Address) - - return *outstruct, err - -} - -// ResolutionCheckpoints is a free data retrieval call binding the contract method 0xa445ece6. -// -// Solidity: function resolutionCheckpoints(uint256 ) view returns(bool initialCheckpointComplete, uint32 subgameIndex, uint128 leftmostPosition, address counteredBy) -func (_FaultDisputeGame *FaultDisputeGameSession) ResolutionCheckpoints(arg0 *big.Int) (struct { - InitialCheckpointComplete bool - SubgameIndex uint32 - LeftmostPosition *big.Int - CounteredBy common.Address -}, error) { - return _FaultDisputeGame.Contract.ResolutionCheckpoints(&_FaultDisputeGame.CallOpts, arg0) -} - -// ResolutionCheckpoints is a free data retrieval call binding the contract method 0xa445ece6. -// -// Solidity: function resolutionCheckpoints(uint256 ) view returns(bool initialCheckpointComplete, uint32 subgameIndex, uint128 leftmostPosition, address counteredBy) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) ResolutionCheckpoints(arg0 *big.Int) (struct { - InitialCheckpointComplete bool - SubgameIndex uint32 - LeftmostPosition *big.Int - CounteredBy common.Address -}, error) { - return _FaultDisputeGame.Contract.ResolutionCheckpoints(&_FaultDisputeGame.CallOpts, arg0) -} - -// ResolvedAt is a free data retrieval call binding the contract method 0x19effeb4. -// -// Solidity: function resolvedAt() view returns(uint64) -func (_FaultDisputeGame *FaultDisputeGameCaller) ResolvedAt(opts *bind.CallOpts) (uint64, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "resolvedAt") - - if err != nil { - return *new(uint64), err - } - - out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) - - return out0, err - -} - -// ResolvedAt is a free data retrieval call binding the contract method 0x19effeb4. -// -// Solidity: function resolvedAt() view returns(uint64) -func (_FaultDisputeGame *FaultDisputeGameSession) ResolvedAt() (uint64, error) { - return _FaultDisputeGame.Contract.ResolvedAt(&_FaultDisputeGame.CallOpts) -} - -// ResolvedAt is a free data retrieval call binding the contract method 0x19effeb4. -// -// Solidity: function resolvedAt() view returns(uint64) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) ResolvedAt() (uint64, error) { - return _FaultDisputeGame.Contract.ResolvedAt(&_FaultDisputeGame.CallOpts) -} - -// ResolvedSubgames is a free data retrieval call binding the contract method 0xfe2bbeb2. -// -// Solidity: function resolvedSubgames(uint256 ) view returns(bool) -func (_FaultDisputeGame *FaultDisputeGameCaller) ResolvedSubgames(opts *bind.CallOpts, arg0 *big.Int) (bool, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "resolvedSubgames", arg0) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// ResolvedSubgames is a free data retrieval call binding the contract method 0xfe2bbeb2. -// -// Solidity: function resolvedSubgames(uint256 ) view returns(bool) -func (_FaultDisputeGame *FaultDisputeGameSession) ResolvedSubgames(arg0 *big.Int) (bool, error) { - return _FaultDisputeGame.Contract.ResolvedSubgames(&_FaultDisputeGame.CallOpts, arg0) -} - -// ResolvedSubgames is a free data retrieval call binding the contract method 0xfe2bbeb2. -// -// Solidity: function resolvedSubgames(uint256 ) view returns(bool) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) ResolvedSubgames(arg0 *big.Int) (bool, error) { - return _FaultDisputeGame.Contract.ResolvedSubgames(&_FaultDisputeGame.CallOpts, arg0) -} - -// RootClaim is a free data retrieval call binding the contract method 0xbcef3b55. -// -// Solidity: function rootClaim() pure returns(bytes32 rootClaim_) -func (_FaultDisputeGame *FaultDisputeGameCaller) RootClaim(opts *bind.CallOpts) ([32]byte, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "rootClaim") - - if err != nil { - return *new([32]byte), err - } - - out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) - - return out0, err - -} - -// RootClaim is a free data retrieval call binding the contract method 0xbcef3b55. -// -// Solidity: function rootClaim() pure returns(bytes32 rootClaim_) -func (_FaultDisputeGame *FaultDisputeGameSession) RootClaim() ([32]byte, error) { - return _FaultDisputeGame.Contract.RootClaim(&_FaultDisputeGame.CallOpts) -} - -// RootClaim is a free data retrieval call binding the contract method 0xbcef3b55. -// -// Solidity: function rootClaim() pure returns(bytes32 rootClaim_) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) RootClaim() ([32]byte, error) { - return _FaultDisputeGame.Contract.RootClaim(&_FaultDisputeGame.CallOpts) -} - -// SplitDepth is a free data retrieval call binding the contract method 0xec5e6308. -// -// Solidity: function splitDepth() view returns(uint256 splitDepth_) -func (_FaultDisputeGame *FaultDisputeGameCaller) SplitDepth(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "splitDepth") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// SplitDepth is a free data retrieval call binding the contract method 0xec5e6308. -// -// Solidity: function splitDepth() view returns(uint256 splitDepth_) -func (_FaultDisputeGame *FaultDisputeGameSession) SplitDepth() (*big.Int, error) { - return _FaultDisputeGame.Contract.SplitDepth(&_FaultDisputeGame.CallOpts) -} - -// SplitDepth is a free data retrieval call binding the contract method 0xec5e6308. -// -// Solidity: function splitDepth() view returns(uint256 splitDepth_) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) SplitDepth() (*big.Int, error) { - return _FaultDisputeGame.Contract.SplitDepth(&_FaultDisputeGame.CallOpts) -} - -// StartingBlockNumber is a free data retrieval call binding the contract method 0x70872aa5. -// -// Solidity: function startingBlockNumber() view returns(uint256 startingBlockNumber_) -func (_FaultDisputeGame *FaultDisputeGameCaller) StartingBlockNumber(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "startingBlockNumber") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// StartingBlockNumber is a free data retrieval call binding the contract method 0x70872aa5. -// -// Solidity: function startingBlockNumber() view returns(uint256 startingBlockNumber_) -func (_FaultDisputeGame *FaultDisputeGameSession) StartingBlockNumber() (*big.Int, error) { - return _FaultDisputeGame.Contract.StartingBlockNumber(&_FaultDisputeGame.CallOpts) -} - -// StartingBlockNumber is a free data retrieval call binding the contract method 0x70872aa5. -// -// Solidity: function startingBlockNumber() view returns(uint256 startingBlockNumber_) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) StartingBlockNumber() (*big.Int, error) { - return _FaultDisputeGame.Contract.StartingBlockNumber(&_FaultDisputeGame.CallOpts) -} - -// StartingOutputRoot is a free data retrieval call binding the contract method 0x57da950e. -// -// Solidity: function startingOutputRoot() view returns(bytes32 root, uint256 l2BlockNumber) -func (_FaultDisputeGame *FaultDisputeGameCaller) StartingOutputRoot(opts *bind.CallOpts) (struct { - Root [32]byte - L2BlockNumber *big.Int -}, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "startingOutputRoot") - - outstruct := new(struct { - Root [32]byte - L2BlockNumber *big.Int - }) - if err != nil { - return *outstruct, err - } - - outstruct.Root = *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) - outstruct.L2BlockNumber = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) - - return *outstruct, err - -} - -// StartingOutputRoot is a free data retrieval call binding the contract method 0x57da950e. -// -// Solidity: function startingOutputRoot() view returns(bytes32 root, uint256 l2BlockNumber) -func (_FaultDisputeGame *FaultDisputeGameSession) StartingOutputRoot() (struct { - Root [32]byte - L2BlockNumber *big.Int -}, error) { - return _FaultDisputeGame.Contract.StartingOutputRoot(&_FaultDisputeGame.CallOpts) -} - -// StartingOutputRoot is a free data retrieval call binding the contract method 0x57da950e. -// -// Solidity: function startingOutputRoot() view returns(bytes32 root, uint256 l2BlockNumber) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) StartingOutputRoot() (struct { - Root [32]byte - L2BlockNumber *big.Int -}, error) { - return _FaultDisputeGame.Contract.StartingOutputRoot(&_FaultDisputeGame.CallOpts) -} - -// StartingRootHash is a free data retrieval call binding the contract method 0x25fc2ace. -// -// Solidity: function startingRootHash() view returns(bytes32 startingRootHash_) -func (_FaultDisputeGame *FaultDisputeGameCaller) StartingRootHash(opts *bind.CallOpts) ([32]byte, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "startingRootHash") - - if err != nil { - return *new([32]byte), err - } - - out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) - - return out0, err - -} - -// StartingRootHash is a free data retrieval call binding the contract method 0x25fc2ace. -// -// Solidity: function startingRootHash() view returns(bytes32 startingRootHash_) -func (_FaultDisputeGame *FaultDisputeGameSession) StartingRootHash() ([32]byte, error) { - return _FaultDisputeGame.Contract.StartingRootHash(&_FaultDisputeGame.CallOpts) -} - -// StartingRootHash is a free data retrieval call binding the contract method 0x25fc2ace. -// -// Solidity: function startingRootHash() view returns(bytes32 startingRootHash_) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) StartingRootHash() ([32]byte, error) { - return _FaultDisputeGame.Contract.StartingRootHash(&_FaultDisputeGame.CallOpts) -} - -// Status is a free data retrieval call binding the contract method 0x200d2ed2. -// -// Solidity: function status() view returns(uint8) -func (_FaultDisputeGame *FaultDisputeGameCaller) Status(opts *bind.CallOpts) (uint8, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "status") - - if err != nil { - return *new(uint8), err - } - - out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) - - return out0, err - -} - -// Status is a free data retrieval call binding the contract method 0x200d2ed2. -// -// Solidity: function status() view returns(uint8) -func (_FaultDisputeGame *FaultDisputeGameSession) Status() (uint8, error) { - return _FaultDisputeGame.Contract.Status(&_FaultDisputeGame.CallOpts) -} - -// Status is a free data retrieval call binding the contract method 0x200d2ed2. -// -// Solidity: function status() view returns(uint8) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) Status() (uint8, error) { - return _FaultDisputeGame.Contract.Status(&_FaultDisputeGame.CallOpts) -} - -// Subgames is a free data retrieval call binding the contract method 0x2ad69aeb. -// -// Solidity: function subgames(uint256 , uint256 ) view returns(uint256) -func (_FaultDisputeGame *FaultDisputeGameCaller) Subgames(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "subgames", arg0, arg1) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// Subgames is a free data retrieval call binding the contract method 0x2ad69aeb. -// -// Solidity: function subgames(uint256 , uint256 ) view returns(uint256) -func (_FaultDisputeGame *FaultDisputeGameSession) Subgames(arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - return _FaultDisputeGame.Contract.Subgames(&_FaultDisputeGame.CallOpts, arg0, arg1) -} - -// Subgames is a free data retrieval call binding the contract method 0x2ad69aeb. -// -// Solidity: function subgames(uint256 , uint256 ) view returns(uint256) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) Subgames(arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { - return _FaultDisputeGame.Contract.Subgames(&_FaultDisputeGame.CallOpts, arg0, arg1) -} - -// Version is a free data retrieval call binding the contract method 0x54fd4d50. -// -// Solidity: function version() view returns(string) -func (_FaultDisputeGame *FaultDisputeGameCaller) Version(opts *bind.CallOpts) (string, error) { - var out []interface{} - err := _FaultDisputeGame.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 (_FaultDisputeGame *FaultDisputeGameSession) Version() (string, error) { - return _FaultDisputeGame.Contract.Version(&_FaultDisputeGame.CallOpts) -} - -// Version is a free data retrieval call binding the contract method 0x54fd4d50. -// -// Solidity: function version() view returns(string) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) Version() (string, error) { - return _FaultDisputeGame.Contract.Version(&_FaultDisputeGame.CallOpts) -} - -// Vm is a free data retrieval call binding the contract method 0x3a768463. -// -// Solidity: function vm() view returns(address vm_) -func (_FaultDisputeGame *FaultDisputeGameCaller) Vm(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "vm") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// Vm is a free data retrieval call binding the contract method 0x3a768463. -// -// Solidity: function vm() view returns(address vm_) -func (_FaultDisputeGame *FaultDisputeGameSession) Vm() (common.Address, error) { - return _FaultDisputeGame.Contract.Vm(&_FaultDisputeGame.CallOpts) -} - -// Vm is a free data retrieval call binding the contract method 0x3a768463. -// -// Solidity: function vm() view returns(address vm_) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) Vm() (common.Address, error) { - return _FaultDisputeGame.Contract.Vm(&_FaultDisputeGame.CallOpts) -} - -// Weth is a free data retrieval call binding the contract method 0x3fc8cef3. -// -// Solidity: function weth() view returns(address weth_) -func (_FaultDisputeGame *FaultDisputeGameCaller) Weth(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _FaultDisputeGame.contract.Call(opts, &out, "weth") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// Weth is a free data retrieval call binding the contract method 0x3fc8cef3. -// -// Solidity: function weth() view returns(address weth_) -func (_FaultDisputeGame *FaultDisputeGameSession) Weth() (common.Address, error) { - return _FaultDisputeGame.Contract.Weth(&_FaultDisputeGame.CallOpts) -} - -// Weth is a free data retrieval call binding the contract method 0x3fc8cef3. -// -// Solidity: function weth() view returns(address weth_) -func (_FaultDisputeGame *FaultDisputeGameCallerSession) Weth() (common.Address, error) { - return _FaultDisputeGame.Contract.Weth(&_FaultDisputeGame.CallOpts) -} - -// AddLocalData is a paid mutator transaction binding the contract method 0xf8f43ff6. -// -// Solidity: function addLocalData(uint256 _ident, uint256 _execLeafIdx, uint256 _partOffset) returns() -func (_FaultDisputeGame *FaultDisputeGameTransactor) AddLocalData(opts *bind.TransactOpts, _ident *big.Int, _execLeafIdx *big.Int, _partOffset *big.Int) (*types.Transaction, error) { - return _FaultDisputeGame.contract.Transact(opts, "addLocalData", _ident, _execLeafIdx, _partOffset) -} - -// AddLocalData is a paid mutator transaction binding the contract method 0xf8f43ff6. -// -// Solidity: function addLocalData(uint256 _ident, uint256 _execLeafIdx, uint256 _partOffset) returns() -func (_FaultDisputeGame *FaultDisputeGameSession) AddLocalData(_ident *big.Int, _execLeafIdx *big.Int, _partOffset *big.Int) (*types.Transaction, error) { - return _FaultDisputeGame.Contract.AddLocalData(&_FaultDisputeGame.TransactOpts, _ident, _execLeafIdx, _partOffset) -} - -// AddLocalData is a paid mutator transaction binding the contract method 0xf8f43ff6. -// -// Solidity: function addLocalData(uint256 _ident, uint256 _execLeafIdx, uint256 _partOffset) returns() -func (_FaultDisputeGame *FaultDisputeGameTransactorSession) AddLocalData(_ident *big.Int, _execLeafIdx *big.Int, _partOffset *big.Int) (*types.Transaction, error) { - return _FaultDisputeGame.Contract.AddLocalData(&_FaultDisputeGame.TransactOpts, _ident, _execLeafIdx, _partOffset) -} - -// Attack is a paid mutator transaction binding the contract method 0x472777c6. -// -// Solidity: function attack(bytes32 _disputed, uint256 _parentIndex, bytes32 _claim) payable returns() -func (_FaultDisputeGame *FaultDisputeGameTransactor) Attack(opts *bind.TransactOpts, _disputed [32]byte, _parentIndex *big.Int, _claim [32]byte) (*types.Transaction, error) { - return _FaultDisputeGame.contract.Transact(opts, "attack", _disputed, _parentIndex, _claim) -} - -// Attack is a paid mutator transaction binding the contract method 0x472777c6. -// -// Solidity: function attack(bytes32 _disputed, uint256 _parentIndex, bytes32 _claim) payable returns() -func (_FaultDisputeGame *FaultDisputeGameSession) Attack(_disputed [32]byte, _parentIndex *big.Int, _claim [32]byte) (*types.Transaction, error) { - return _FaultDisputeGame.Contract.Attack(&_FaultDisputeGame.TransactOpts, _disputed, _parentIndex, _claim) -} - -// Attack is a paid mutator transaction binding the contract method 0x472777c6. -// -// Solidity: function attack(bytes32 _disputed, uint256 _parentIndex, bytes32 _claim) payable returns() -func (_FaultDisputeGame *FaultDisputeGameTransactorSession) Attack(_disputed [32]byte, _parentIndex *big.Int, _claim [32]byte) (*types.Transaction, error) { - return _FaultDisputeGame.Contract.Attack(&_FaultDisputeGame.TransactOpts, _disputed, _parentIndex, _claim) -} - -// ChallengeRootL2Block is a paid mutator transaction binding the contract method 0x01935130. -// -// Solidity: function challengeRootL2Block((bytes32,bytes32,bytes32,bytes32) _outputRootProof, bytes _headerRLP) returns() -func (_FaultDisputeGame *FaultDisputeGameTransactor) ChallengeRootL2Block(opts *bind.TransactOpts, _outputRootProof TypesOutputRootProof, _headerRLP []byte) (*types.Transaction, error) { - return _FaultDisputeGame.contract.Transact(opts, "challengeRootL2Block", _outputRootProof, _headerRLP) -} - -// ChallengeRootL2Block is a paid mutator transaction binding the contract method 0x01935130. -// -// Solidity: function challengeRootL2Block((bytes32,bytes32,bytes32,bytes32) _outputRootProof, bytes _headerRLP) returns() -func (_FaultDisputeGame *FaultDisputeGameSession) ChallengeRootL2Block(_outputRootProof TypesOutputRootProof, _headerRLP []byte) (*types.Transaction, error) { - return _FaultDisputeGame.Contract.ChallengeRootL2Block(&_FaultDisputeGame.TransactOpts, _outputRootProof, _headerRLP) -} - -// ChallengeRootL2Block is a paid mutator transaction binding the contract method 0x01935130. -// -// Solidity: function challengeRootL2Block((bytes32,bytes32,bytes32,bytes32) _outputRootProof, bytes _headerRLP) returns() -func (_FaultDisputeGame *FaultDisputeGameTransactorSession) ChallengeRootL2Block(_outputRootProof TypesOutputRootProof, _headerRLP []byte) (*types.Transaction, error) { - return _FaultDisputeGame.Contract.ChallengeRootL2Block(&_FaultDisputeGame.TransactOpts, _outputRootProof, _headerRLP) -} - -// ClaimCredit is a paid mutator transaction binding the contract method 0x60e27464. -// -// Solidity: function claimCredit(address _recipient) returns() -func (_FaultDisputeGame *FaultDisputeGameTransactor) ClaimCredit(opts *bind.TransactOpts, _recipient common.Address) (*types.Transaction, error) { - return _FaultDisputeGame.contract.Transact(opts, "claimCredit", _recipient) -} - -// ClaimCredit is a paid mutator transaction binding the contract method 0x60e27464. -// -// Solidity: function claimCredit(address _recipient) returns() -func (_FaultDisputeGame *FaultDisputeGameSession) ClaimCredit(_recipient common.Address) (*types.Transaction, error) { - return _FaultDisputeGame.Contract.ClaimCredit(&_FaultDisputeGame.TransactOpts, _recipient) -} - -// ClaimCredit is a paid mutator transaction binding the contract method 0x60e27464. -// -// Solidity: function claimCredit(address _recipient) returns() -func (_FaultDisputeGame *FaultDisputeGameTransactorSession) ClaimCredit(_recipient common.Address) (*types.Transaction, error) { - return _FaultDisputeGame.Contract.ClaimCredit(&_FaultDisputeGame.TransactOpts, _recipient) -} - -// Defend is a paid mutator transaction binding the contract method 0x7b0f0adc. -// -// Solidity: function defend(bytes32 _disputed, uint256 _parentIndex, bytes32 _claim) payable returns() -func (_FaultDisputeGame *FaultDisputeGameTransactor) Defend(opts *bind.TransactOpts, _disputed [32]byte, _parentIndex *big.Int, _claim [32]byte) (*types.Transaction, error) { - return _FaultDisputeGame.contract.Transact(opts, "defend", _disputed, _parentIndex, _claim) -} - -// Defend is a paid mutator transaction binding the contract method 0x7b0f0adc. -// -// Solidity: function defend(bytes32 _disputed, uint256 _parentIndex, bytes32 _claim) payable returns() -func (_FaultDisputeGame *FaultDisputeGameSession) Defend(_disputed [32]byte, _parentIndex *big.Int, _claim [32]byte) (*types.Transaction, error) { - return _FaultDisputeGame.Contract.Defend(&_FaultDisputeGame.TransactOpts, _disputed, _parentIndex, _claim) -} - -// Defend is a paid mutator transaction binding the contract method 0x7b0f0adc. -// -// Solidity: function defend(bytes32 _disputed, uint256 _parentIndex, bytes32 _claim) payable returns() -func (_FaultDisputeGame *FaultDisputeGameTransactorSession) Defend(_disputed [32]byte, _parentIndex *big.Int, _claim [32]byte) (*types.Transaction, error) { - return _FaultDisputeGame.Contract.Defend(&_FaultDisputeGame.TransactOpts, _disputed, _parentIndex, _claim) -} - -// Initialize is a paid mutator transaction binding the contract method 0x8129fc1c. -// -// Solidity: function initialize() payable returns() -func (_FaultDisputeGame *FaultDisputeGameTransactor) Initialize(opts *bind.TransactOpts) (*types.Transaction, error) { - return _FaultDisputeGame.contract.Transact(opts, "initialize") -} - -// Initialize is a paid mutator transaction binding the contract method 0x8129fc1c. -// -// Solidity: function initialize() payable returns() -func (_FaultDisputeGame *FaultDisputeGameSession) Initialize() (*types.Transaction, error) { - return _FaultDisputeGame.Contract.Initialize(&_FaultDisputeGame.TransactOpts) -} - -// Initialize is a paid mutator transaction binding the contract method 0x8129fc1c. -// -// Solidity: function initialize() payable returns() -func (_FaultDisputeGame *FaultDisputeGameTransactorSession) Initialize() (*types.Transaction, error) { - return _FaultDisputeGame.Contract.Initialize(&_FaultDisputeGame.TransactOpts) -} - -// Move is a paid mutator transaction binding the contract method 0x6f034409. -// -// Solidity: function move(bytes32 _disputed, uint256 _challengeIndex, bytes32 _claim, bool _isAttack) payable returns() -func (_FaultDisputeGame *FaultDisputeGameTransactor) Move(opts *bind.TransactOpts, _disputed [32]byte, _challengeIndex *big.Int, _claim [32]byte, _isAttack bool) (*types.Transaction, error) { - return _FaultDisputeGame.contract.Transact(opts, "move", _disputed, _challengeIndex, _claim, _isAttack) -} - -// Move is a paid mutator transaction binding the contract method 0x6f034409. -// -// Solidity: function move(bytes32 _disputed, uint256 _challengeIndex, bytes32 _claim, bool _isAttack) payable returns() -func (_FaultDisputeGame *FaultDisputeGameSession) Move(_disputed [32]byte, _challengeIndex *big.Int, _claim [32]byte, _isAttack bool) (*types.Transaction, error) { - return _FaultDisputeGame.Contract.Move(&_FaultDisputeGame.TransactOpts, _disputed, _challengeIndex, _claim, _isAttack) -} - -// Move is a paid mutator transaction binding the contract method 0x6f034409. -// -// Solidity: function move(bytes32 _disputed, uint256 _challengeIndex, bytes32 _claim, bool _isAttack) payable returns() -func (_FaultDisputeGame *FaultDisputeGameTransactorSession) Move(_disputed [32]byte, _challengeIndex *big.Int, _claim [32]byte, _isAttack bool) (*types.Transaction, error) { - return _FaultDisputeGame.Contract.Move(&_FaultDisputeGame.TransactOpts, _disputed, _challengeIndex, _claim, _isAttack) -} - -// Resolve is a paid mutator transaction binding the contract method 0x2810e1d6. -// -// Solidity: function resolve() returns(uint8 status_) -func (_FaultDisputeGame *FaultDisputeGameTransactor) Resolve(opts *bind.TransactOpts) (*types.Transaction, error) { - return _FaultDisputeGame.contract.Transact(opts, "resolve") -} - -// Resolve is a paid mutator transaction binding the contract method 0x2810e1d6. -// -// Solidity: function resolve() returns(uint8 status_) -func (_FaultDisputeGame *FaultDisputeGameSession) Resolve() (*types.Transaction, error) { - return _FaultDisputeGame.Contract.Resolve(&_FaultDisputeGame.TransactOpts) -} - -// Resolve is a paid mutator transaction binding the contract method 0x2810e1d6. -// -// Solidity: function resolve() returns(uint8 status_) -func (_FaultDisputeGame *FaultDisputeGameTransactorSession) Resolve() (*types.Transaction, error) { - return _FaultDisputeGame.Contract.Resolve(&_FaultDisputeGame.TransactOpts) -} - -// ResolveClaim is a paid mutator transaction binding the contract method 0x03c2924d. -// -// Solidity: function resolveClaim(uint256 _claimIndex, uint256 _numToResolve) returns() -func (_FaultDisputeGame *FaultDisputeGameTransactor) ResolveClaim(opts *bind.TransactOpts, _claimIndex *big.Int, _numToResolve *big.Int) (*types.Transaction, error) { - return _FaultDisputeGame.contract.Transact(opts, "resolveClaim", _claimIndex, _numToResolve) -} - -// ResolveClaim is a paid mutator transaction binding the contract method 0x03c2924d. -// -// Solidity: function resolveClaim(uint256 _claimIndex, uint256 _numToResolve) returns() -func (_FaultDisputeGame *FaultDisputeGameSession) ResolveClaim(_claimIndex *big.Int, _numToResolve *big.Int) (*types.Transaction, error) { - return _FaultDisputeGame.Contract.ResolveClaim(&_FaultDisputeGame.TransactOpts, _claimIndex, _numToResolve) -} - -// ResolveClaim is a paid mutator transaction binding the contract method 0x03c2924d. -// -// Solidity: function resolveClaim(uint256 _claimIndex, uint256 _numToResolve) returns() -func (_FaultDisputeGame *FaultDisputeGameTransactorSession) ResolveClaim(_claimIndex *big.Int, _numToResolve *big.Int) (*types.Transaction, error) { - return _FaultDisputeGame.Contract.ResolveClaim(&_FaultDisputeGame.TransactOpts, _claimIndex, _numToResolve) -} - -// Step is a paid mutator transaction binding the contract method 0xd8cc1a3c. -// -// Solidity: function step(uint256 _claimIndex, bool _isAttack, bytes _stateData, bytes _proof) returns() -func (_FaultDisputeGame *FaultDisputeGameTransactor) Step(opts *bind.TransactOpts, _claimIndex *big.Int, _isAttack bool, _stateData []byte, _proof []byte) (*types.Transaction, error) { - return _FaultDisputeGame.contract.Transact(opts, "step", _claimIndex, _isAttack, _stateData, _proof) -} - -// Step is a paid mutator transaction binding the contract method 0xd8cc1a3c. -// -// Solidity: function step(uint256 _claimIndex, bool _isAttack, bytes _stateData, bytes _proof) returns() -func (_FaultDisputeGame *FaultDisputeGameSession) Step(_claimIndex *big.Int, _isAttack bool, _stateData []byte, _proof []byte) (*types.Transaction, error) { - return _FaultDisputeGame.Contract.Step(&_FaultDisputeGame.TransactOpts, _claimIndex, _isAttack, _stateData, _proof) -} - -// Step is a paid mutator transaction binding the contract method 0xd8cc1a3c. -// -// Solidity: function step(uint256 _claimIndex, bool _isAttack, bytes _stateData, bytes _proof) returns() -func (_FaultDisputeGame *FaultDisputeGameTransactorSession) Step(_claimIndex *big.Int, _isAttack bool, _stateData []byte, _proof []byte) (*types.Transaction, error) { - return _FaultDisputeGame.Contract.Step(&_FaultDisputeGame.TransactOpts, _claimIndex, _isAttack, _stateData, _proof) -} - -// FaultDisputeGameMoveIterator is returned from FilterMove and is used to iterate over the raw logs and unpacked data for Move events raised by the FaultDisputeGame contract. -type FaultDisputeGameMoveIterator struct { - Event *FaultDisputeGameMove // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *FaultDisputeGameMoveIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(FaultDisputeGameMove) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(FaultDisputeGameMove) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *FaultDisputeGameMoveIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *FaultDisputeGameMoveIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// FaultDisputeGameMove represents a Move event raised by the FaultDisputeGame contract. -type FaultDisputeGameMove struct { - ParentIndex *big.Int - Claim [32]byte - Claimant common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterMove is a free log retrieval operation binding the contract event 0x9b3245740ec3b155098a55be84957a4da13eaf7f14a8bc6f53126c0b9350f2be. -// -// Solidity: event Move(uint256 indexed parentIndex, bytes32 indexed claim, address indexed claimant) -func (_FaultDisputeGame *FaultDisputeGameFilterer) FilterMove(opts *bind.FilterOpts, parentIndex []*big.Int, claim [][32]byte, claimant []common.Address) (*FaultDisputeGameMoveIterator, error) { - - var parentIndexRule []interface{} - for _, parentIndexItem := range parentIndex { - parentIndexRule = append(parentIndexRule, parentIndexItem) - } - var claimRule []interface{} - for _, claimItem := range claim { - claimRule = append(claimRule, claimItem) - } - var claimantRule []interface{} - for _, claimantItem := range claimant { - claimantRule = append(claimantRule, claimantItem) - } - - logs, sub, err := _FaultDisputeGame.contract.FilterLogs(opts, "Move", parentIndexRule, claimRule, claimantRule) - if err != nil { - return nil, err - } - return &FaultDisputeGameMoveIterator{contract: _FaultDisputeGame.contract, event: "Move", logs: logs, sub: sub}, nil -} - -// WatchMove is a free log subscription operation binding the contract event 0x9b3245740ec3b155098a55be84957a4da13eaf7f14a8bc6f53126c0b9350f2be. -// -// Solidity: event Move(uint256 indexed parentIndex, bytes32 indexed claim, address indexed claimant) -func (_FaultDisputeGame *FaultDisputeGameFilterer) WatchMove(opts *bind.WatchOpts, sink chan<- *FaultDisputeGameMove, parentIndex []*big.Int, claim [][32]byte, claimant []common.Address) (event.Subscription, error) { - - var parentIndexRule []interface{} - for _, parentIndexItem := range parentIndex { - parentIndexRule = append(parentIndexRule, parentIndexItem) - } - var claimRule []interface{} - for _, claimItem := range claim { - claimRule = append(claimRule, claimItem) - } - var claimantRule []interface{} - for _, claimantItem := range claimant { - claimantRule = append(claimantRule, claimantItem) - } - - logs, sub, err := _FaultDisputeGame.contract.WatchLogs(opts, "Move", parentIndexRule, claimRule, claimantRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(FaultDisputeGameMove) - if err := _FaultDisputeGame.contract.UnpackLog(event, "Move", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseMove is a log parse operation binding the contract event 0x9b3245740ec3b155098a55be84957a4da13eaf7f14a8bc6f53126c0b9350f2be. -// -// Solidity: event Move(uint256 indexed parentIndex, bytes32 indexed claim, address indexed claimant) -func (_FaultDisputeGame *FaultDisputeGameFilterer) ParseMove(log types.Log) (*FaultDisputeGameMove, error) { - event := new(FaultDisputeGameMove) - if err := _FaultDisputeGame.contract.UnpackLog(event, "Move", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// FaultDisputeGameResolvedIterator is returned from FilterResolved and is used to iterate over the raw logs and unpacked data for Resolved events raised by the FaultDisputeGame contract. -type FaultDisputeGameResolvedIterator struct { - Event *FaultDisputeGameResolved // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *FaultDisputeGameResolvedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(FaultDisputeGameResolved) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(FaultDisputeGameResolved) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *FaultDisputeGameResolvedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *FaultDisputeGameResolvedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// FaultDisputeGameResolved represents a Resolved event raised by the FaultDisputeGame contract. -type FaultDisputeGameResolved struct { - Status uint8 - Raw types.Log // Blockchain specific contextual infos -} - -// FilterResolved is a free log retrieval operation binding the contract event 0x5e186f09b9c93491f14e277eea7faa5de6a2d4bda75a79af7a3684fbfb42da60. -// -// Solidity: event Resolved(uint8 indexed status) -func (_FaultDisputeGame *FaultDisputeGameFilterer) FilterResolved(opts *bind.FilterOpts, status []uint8) (*FaultDisputeGameResolvedIterator, error) { - - var statusRule []interface{} - for _, statusItem := range status { - statusRule = append(statusRule, statusItem) - } - - logs, sub, err := _FaultDisputeGame.contract.FilterLogs(opts, "Resolved", statusRule) - if err != nil { - return nil, err - } - return &FaultDisputeGameResolvedIterator{contract: _FaultDisputeGame.contract, event: "Resolved", logs: logs, sub: sub}, nil -} - -// WatchResolved is a free log subscription operation binding the contract event 0x5e186f09b9c93491f14e277eea7faa5de6a2d4bda75a79af7a3684fbfb42da60. -// -// Solidity: event Resolved(uint8 indexed status) -func (_FaultDisputeGame *FaultDisputeGameFilterer) WatchResolved(opts *bind.WatchOpts, sink chan<- *FaultDisputeGameResolved, status []uint8) (event.Subscription, error) { - - var statusRule []interface{} - for _, statusItem := range status { - statusRule = append(statusRule, statusItem) - } - - logs, sub, err := _FaultDisputeGame.contract.WatchLogs(opts, "Resolved", statusRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(FaultDisputeGameResolved) - if err := _FaultDisputeGame.contract.UnpackLog(event, "Resolved", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseResolved is a log parse operation binding the contract event 0x5e186f09b9c93491f14e277eea7faa5de6a2d4bda75a79af7a3684fbfb42da60. -// -// Solidity: event Resolved(uint8 indexed status) -func (_FaultDisputeGame *FaultDisputeGameFilterer) ParseResolved(log types.Log) (*FaultDisputeGameResolved, error) { - event := new(FaultDisputeGameResolved) - if err := _FaultDisputeGame.contract.UnpackLog(event, "Resolved", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} diff --git a/op-dispute-mon/bindings/optimismportal.go b/op-dispute-mon/bindings/optimismportal.go deleted file mode 100644 index 3fb3ed0cd59ab..0000000000000 --- a/op-dispute-mon/bindings/optimismportal.go +++ /dev/null @@ -1,1478 +0,0 @@ -// 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 -) - -// TypesOutputRootProof is an auto generated low-level Go binding around an user-defined struct. -type TypesOutputRootProof struct { - Version [32]byte - StateRoot [32]byte - MessagePasserStorageRoot [32]byte - LatestBlockhash [32]byte -} - -// TypesWithdrawalTransaction is an auto generated low-level Go binding around an user-defined struct. -type TypesWithdrawalTransaction struct { - Nonce *big.Int - Sender common.Address - Target common.Address - Value *big.Int - GasLimit *big.Int - Data []byte -} - -// OptimismPortalMetaData contains all meta data concerning the OptimismPortal contract. -var OptimismPortalMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"receive\",\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"balance\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"depositERC20Transaction\",\"inputs\":[{\"name\":\"_to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_mint\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_value\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_gasLimit\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"_isCreation\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"_data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"depositTransaction\",\"inputs\":[{\"name\":\"_to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_gasLimit\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"_isCreation\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"_data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"donateETH\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"finalizeWithdrawalTransaction\",\"inputs\":[{\"name\":\"_tx\",\"type\":\"tuple\",\"internalType\":\"structTypes.WithdrawalTransaction\",\"components\":[{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"gasLimit\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizedWithdrawals\",\"inputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"gasPayingToken\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"decimals_\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"guardian\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_l2Oracle\",\"type\":\"address\",\"internalType\":\"contractL2OutputOracle\"},{\"name\":\"_systemConfig\",\"type\":\"address\",\"internalType\":\"contractSystemConfig\"},{\"name\":\"_superchainConfig\",\"type\":\"address\",\"internalType\":\"contractSuperchainConfig\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"isOutputFinalized\",\"inputs\":[{\"name\":\"_l2OutputIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"l2Oracle\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractL2OutputOracle\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"l2Sender\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"minimumGasLimit\",\"inputs\":[{\"name\":\"_byteCount\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"params\",\"inputs\":[],\"outputs\":[{\"name\":\"prevBaseFee\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"prevBoughtGas\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"prevBlockNum\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"paused_\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proveWithdrawalTransaction\",\"inputs\":[{\"name\":\"_tx\",\"type\":\"tuple\",\"internalType\":\"structTypes.WithdrawalTransaction\",\"components\":[{\"name\":\"nonce\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"gasLimit\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"_l2OutputIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_outputRootProof\",\"type\":\"tuple\",\"internalType\":\"structTypes.OutputRootProof\",\"components\":[{\"name\":\"version\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"stateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"messagePasserStorageRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"latestBlockhash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"_withdrawalProof\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"provenWithdrawals\",\"inputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"outputRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"timestamp\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"l2OutputIndex\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setGasPayingToken\",\"inputs\":[{\"name\":\"_token\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_decimals\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"_name\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_symbol\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"superchainConfig\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractSuperchainConfig\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"systemConfig\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractSystemConfig\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"version\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TransactionDeposited\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"version\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"opaqueData\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"WithdrawalFinalized\",\"inputs\":[{\"name\":\"withdrawalHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"success\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"WithdrawalProven\",\"inputs\":[{\"name\":\"withdrawalHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"from\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"BadTarget\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"CallPaused\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"GasEstimation\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"LargeCalldata\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NoValue\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NonReentrant\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyCustomGasToken\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OutOfGas\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SmallGasLimit\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"TransferFailed\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"Unauthorized\",\"inputs\":[]}]", - Bin: "0x60806040523480156200001157600080fd5b50620000206000808062000026565b6200028f565b600054610100900460ff1615808015620000475750600054600160ff909116105b806200007757506200006430620001c160201b62001ff31760201c565b15801562000077575060005460ff166001145b620000e05760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff19166001179055801562000104576000805461ff0019166101001790555b603680546001600160a01b03199081166001600160a01b03878116919091179092556037805490911685831617905560358054610100600160a81b03191661010085841602179055603254166200016a57603280546001600160a01b03191661dead1790555b62000174620001d0565b8015620001bb576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b6001600160a01b03163b151590565b600054610100900460ff166200023d5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401620000d7565b600154600160c01b90046001600160401b03166000036200028d5760408051606081018252633b9aca0080825260006020830152436001600160401b031691909201819052600160c01b02176001555b565b615f6d806200029f6000396000f3fe60806040526004361061016e5760003560e01c80638b4c40b0116100cb578063a35d99df1161007f578063cff0ab9611610059578063cff0ab961461049c578063e965084c1461053d578063e9e05c42146105c957600080fd5b8063a35d99df14610420578063b69ef8a814610459578063c0c53b8b1461047c57600080fd5b80639b5f694a116100b05780639b5f694a146103965780639bf62d82146103c3578063a14238e7146103f057600080fd5b80638b4c40b0146101935780638c3152e91461037657600080fd5b80634870496f116101225780635c975abb116101075780635c975abb146103115780636dbffb781461033657806371cfaa3f1461035657600080fd5b80634870496f1461029b57806354fd4d50146102bb57600080fd5b806335e80ab31161015357806335e80ab3146102115780634397dfef14610243578063452a93201461028657600080fd5b8063149f2f221461019a57806333d7e2bd146101ba57600080fd5b36610195576101933334620186a06000604051806020016040528060008152506105d7565b005b600080fd5b3480156101a657600080fd5b506101936101b536600461538d565b61067c565b3480156101c657600080fd5b506037546101e79073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561021d57600080fd5b506035546101e790610100900473ffffffffffffffffffffffffffffffffffffffff1681565b34801561024f57600080fd5b506102586108be565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835260ff909116602083015201610208565b34801561029257600080fd5b506101e761095b565b3480156102a757600080fd5b506101936102b63660046154c1565b6109f3565b3480156102c757600080fd5b506103046040518060400160405280601b81526020017f322e372e302d626574612b637573746f6d2d6761732d746f6b656e000000000081525081565b6040516102089190615613565b34801561031d57600080fd5b50610326610fa0565b6040519015158152602001610208565b34801561034257600080fd5b50610326610351366004615626565b611033565b34801561036257600080fd5b5061019361037136600461564e565b6110ee565b34801561038257600080fd5b50610193610391366004615694565b6112b0565b3480156103a257600080fd5b506036546101e79073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103cf57600080fd5b506032546101e79073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103fc57600080fd5b5061032661040b366004615626565b60336020526000908152604090205460ff1681565b34801561042c57600080fd5b5061044061043b3660046156d1565b611d32565b60405167ffffffffffffffff9091168152602001610208565b34801561046557600080fd5b5061046e611d4b565b604051908152602001610208565b34801561048857600080fd5b506101936104973660046156ec565b611da5565b3480156104a857600080fd5b50600154610504906fffffffffffffffffffffffffffffffff81169067ffffffffffffffff7001000000000000000000000000000000008204811691780100000000000000000000000000000000000000000000000090041683565b604080516fffffffffffffffffffffffffffffffff909416845267ffffffffffffffff9283166020850152911690820152606001610208565b34801561054957600080fd5b5061059b610558366004615626565b603460205260009081526040902080546001909101546fffffffffffffffffffffffffffffffff8082169170010000000000000000000000000000000090041683565b604080519384526fffffffffffffffffffffffffffffffff9283166020850152911690820152606001610208565b6101936105d7366004615737565b8260005a905060006105e76108be565b50905073ffffffffffffffffffffffffffffffffffffffff811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480159061062357503415155b1561065a576040517ff2365b5b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61066888348989898961200f565b5061067382826121bb565b50505050505050565b8260005a9050600061068c6108be565b5090507fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8216016106fe576040517f0eaf3c0f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa15801561076b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078f91906157b4565b90506107b373ffffffffffffffffffffffffffffffffffffffff831633308c612488565b6107bd89826157fc565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa158015610827573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061084b91906157b4565b14610882576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b88603d600082825461089491906157fc565b909155506108a890508a8a8a8a8a8a61200f565b50506108b482826121bb565b5050505050505050565b603754604080517f4397dfef0000000000000000000000000000000000000000000000000000000081528151600093849373ffffffffffffffffffffffffffffffffffffffff90911692634397dfef92600480830193928290030181865afa15801561092e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109529190615814565b90939092509050565b6000603560019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663452a93206040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ee919061584e565b905090565b6109fb610fa0565b15610a32576040517ff480973e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3073ffffffffffffffffffffffffffffffffffffffff16856040015173ffffffffffffffffffffffffffffffffffffffff1603610a9b576040517f13496fda00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6036546040517fa25ae5570000000000000000000000000000000000000000000000000000000081526004810186905260009173ffffffffffffffffffffffffffffffffffffffff169063a25ae55790602401606060405180830381865afa158015610b0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2f919061588b565b519050610b49610b44368690038601866158f0565b612564565b8114610bdc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4f7074696d69736d506f7274616c3a20696e76616c6964206f7574707574207260448201527f6f6f742070726f6f66000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6000610be7876125c0565b6000818152603460209081526040918290208251606081018452815481526001909101546fffffffffffffffffffffffffffffffff8082169383018490527001000000000000000000000000000000009091041692810192909252919250901580610cfd5750805160365460408084015190517fa25ae5570000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff9091169063a25ae55790602401606060405180830381865afa158015610cd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf9919061588b565b5114155b610d89576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f4f7074696d69736d506f7274616c3a207769746864726177616c20686173682060448201527f68617320616c7265616479206265656e2070726f76656e0000000000000000006064820152608401610bd3565b60408051602081018490526000918101829052606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201209083018190529250610e529101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828201909152600182527f0100000000000000000000000000000000000000000000000000000000000000602083015290610e48888a615956565b8a604001356125f0565b610ede576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4f7074696d69736d506f7274616c3a20696e76616c696420776974686472617760448201527f616c20696e636c7573696f6e2070726f6f6600000000000000000000000000006064820152608401610bd3565b604080516060810182528581526fffffffffffffffffffffffffffffffff42811660208084019182528c831684860190815260008981526034835286812095518655925190518416700100000000000000000000000000000000029316929092176001909301929092558b830151908c0151925173ffffffffffffffffffffffffffffffffffffffff918216939091169186917f67a6208cfcc0801d50f6cbe764733f4fddf66ac0b04442061a8a8c0cb6b63f629190a4505050505050505050565b6000603560019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561100f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ee91906159da565b6036546040517fa25ae557000000000000000000000000000000000000000000000000000000008152600481018390526000916110e89173ffffffffffffffffffffffffffffffffffffffff9091169063a25ae55790602401606060405180830381865afa1580156110a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110cd919061588b565b602001516fffffffffffffffffffffffffffffffff16612614565b92915050565b60375473ffffffffffffffffffffffffffffffffffffffff16331461113f576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61114b620138806126ba565b60405173ffffffffffffffffffffffffffffffffffffffff8516602482015260ff8416604482015260648101839052608481018290526000907342000000000000000000000000000000000000159073deaddeaddeaddeaddeaddeaddeaddeaddead0001907fb3813568d9991fc951961fcb4c784893574240a28925604d09fc577c55bb7c3290849081906201388090829060a401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f71cfaa3f000000000000000000000000000000000000000000000000000000001790529051611268969594939291016159f7565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526112a091615613565b60405180910390a450505050565b565b6112b8610fa0565b156112ef576040517ff480973e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60325473ffffffffffffffffffffffffffffffffffffffff1661dead14611342576040517f9396d15600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061134d826125c0565b60008181526034602090815260408083208151606081018352815481526001909101546fffffffffffffffffffffffffffffffff80821694830185905270010000000000000000000000000000000090910416918101919091529293509003611438576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4f7074696d69736d506f7274616c3a207769746864726177616c20686173206e60448201527f6f74206265656e2070726f76656e2079657400000000000000000000000000006064820152608401610bd3565b603660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663887862726040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c991906157b4565b81602001516fffffffffffffffffffffffffffffffff161015611594576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604b60248201527f4f7074696d69736d506f7274616c3a207769746864726177616c2074696d657360448201527f74616d70206c657373207468616e204c32204f7261636c65207374617274696e60648201527f672074696d657374616d70000000000000000000000000000000000000000000608482015260a401610bd3565b6115b381602001516fffffffffffffffffffffffffffffffff16612614565b611665576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604560248201527f4f7074696d69736d506f7274616c3a2070726f76656e2077697468647261776160448201527f6c2066696e616c697a6174696f6e20706572696f6420686173206e6f7420656c60648201527f6170736564000000000000000000000000000000000000000000000000000000608482015260a401610bd3565b60365460408281015190517fa25ae5570000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff909116600482015260009173ffffffffffffffffffffffffffffffffffffffff169063a25ae55790602401606060405180830381865afa1580156116ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611710919061588b565b82518151919250146117ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604960248201527f4f7074696d69736d506f7274616c3a206f757470757420726f6f742070726f7660448201527f656e206973206e6f74207468652073616d652061732063757272656e74206f7560648201527f7470757420726f6f740000000000000000000000000000000000000000000000608482015260a401610bd3565b6117e981602001516fffffffffffffffffffffffffffffffff16612614565b61189b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604360248201527f4f7074696d69736d506f7274616c3a206f75747075742070726f706f73616c2060448201527f66696e616c697a6174696f6e20706572696f6420686173206e6f7420656c617060648201527f7365640000000000000000000000000000000000000000000000000000000000608482015260a401610bd3565b60008381526033602052604090205460ff161561193a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f4f7074696d69736d506f7274616c3a207769746864726177616c20686173206160448201527f6c7265616479206265656e2066696e616c697a656400000000000000000000006064820152608401610bd3565b6000838152603360209081526040822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558501516032805473ffffffffffffffffffffffffffffffffffffffff9092167fffffffffffffffffffffffff0000000000000000000000000000000000000000909216919091179055806119c56108be565b5090507fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff821601611a2857611a218660400151876080015188606001518960a00151612716565b9150611c7b565b8073ffffffffffffffffffffffffffffffffffffffff16866040015173ffffffffffffffffffffffffffffffffffffffff1603611a91576040517f13496fda00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606086015115611c52578560600151603d6000828254611ab19190615a5c565b90915550506040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015611b23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b4791906157b4565b9050611b7c876040015188606001518473ffffffffffffffffffffffffffffffffffffffff166127749092919063ffffffff16565b6060870151611b8b9082615a5c565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa158015611bf5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c1991906157b4565b14611c50576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b60a08601515115611c7657611a218660400151876080015160008960a00151612716565b600191505b603280547fffffffffffffffffffffffff00000000000000000000000000000000000000001661dead17905560405185907fdb5c7652857aa163daadd670e116628fb42e869d8ac4251ef8971d9e5727df1b90611cdd90851515815260200190565b60405180910390a281158015611cf35750326001145b15611d2a576040517feeae4ed300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b6000611d3f826010615a73565b6110e890615208615aa3565b600080611d566108be565b5090507fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff821601611d9d574791505090565b5050603d5490565b600054610100900460ff1615808015611dc55750600054600160ff909116105b80611ddf5750303b158015611ddf575060005460ff166001145b611e6b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610bd3565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015611ec957600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b603680547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff8781169190911790925560378054909116858316179055603580547fffffffffffffffffffffff0000000000000000000000000000000000000000ff166101008584160217905560325416611f8257603280547fffffffffffffffffffffffff00000000000000000000000000000000000000001661dead1790555b611f8a6127cf565b8015611fed57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b818015612031575073ffffffffffffffffffffffffffffffffffffffff861615155b15612068576040517f13496fda00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6120728151611d32565b67ffffffffffffffff168367ffffffffffffffff1610156120bf576040517f4929b80800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6201d4c0815111156120fd576040517f73052b0f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3332811461211e575033731111000000000000000000000000000000001111015b600086868686866040516020016121399594939291906159f7565b604051602081830303815290604052905060008873ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fb3813568d9991fc951961fcb4c784893574240a28925604d09fc577c55bb7c32846040516121a99190615613565b60405180910390a45050505050505050565b6001546000906121f1907801000000000000000000000000000000000000000000000000900467ffffffffffffffff1643615a5c565b905060006121fd6128e2565b90506000816020015160ff16826000015163ffffffff1661221e9190615afe565b9050821561235557600154600090612255908390700100000000000000000000000000000000900467ffffffffffffffff16615b66565b90506000836040015160ff168361226c9190615bda565b60015461228c9084906fffffffffffffffffffffffffffffffff16615bda565b6122969190615afe565b6001549091506000906122e7906122c09084906fffffffffffffffffffffffffffffffff16615c96565b866060015163ffffffff168760a001516fffffffffffffffffffffffffffffffff166129a3565b90506001861115612316576123136122c082876040015160ff1660018a61230e9190615a5c565b6129c2565b90505b6fffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000067ffffffffffffffff4316021760015550505b60018054869190601090612388908490700100000000000000000000000000000000900467ffffffffffffffff16615aa3565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550816000015163ffffffff16600160000160109054906101000a900467ffffffffffffffff1667ffffffffffffffff161315612415576040517f77ebef4d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600154600090612441906fffffffffffffffffffffffffffffffff1667ffffffffffffffff8816615d0a565b9050600061245348633b9aca00612a17565b61245d9083615d47565b905060005a61246c9088615a5c565b9050808211156108b4576108b46124838284615a5c565b612a2e565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052611fed9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612a57565b600081600001518260200151836040015184606001516040516020016125a3949392919093845260208401929092526040830152606082015260800190565b604051602081830303815290604052805190602001209050919050565b80516020808301516040808501516060860151608087015160a088015193516000976125a3979096959101615d5b565b6000806125fc86612b63565b905061260a81868686612b95565b9695505050505050565b603654604080517ff4daa291000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff169163f4daa2919160048083019260209291908290030181865afa158015612684573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126a891906157b4565b6126b290836157fc565b421192915050565b600180548291906010906126ed908490700100000000000000000000000000000000900467ffffffffffffffff16615aa3565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555050565b6000806000612726866000612bc5565b90508061275c576308c379a06000526020805278185361666543616c6c3a204e6f7420656e6f756768206761736058526064601cfd5b600080855160208701888b5af1979650505050505050565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526127ca9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064016124e2565b505050565b600054610100900460ff16612866576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610bd3565b6001547801000000000000000000000000000000000000000000000000900467ffffffffffffffff166000036112ae5760408051606081018252633b9aca00808252600060208301524367ffffffffffffffff169190920181905278010000000000000000000000000000000000000000000000000217600155565b6040805160c08082018352600080835260208301819052828401819052606083018190526080830181905260a083015260375483517fcc731b020000000000000000000000000000000000000000000000000000000081529351929373ffffffffffffffffffffffffffffffffffffffff9091169263cc731b02926004808401939192918290030181865afa15801561297f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ee9190615dc6565b60006129b86129b28585612be3565b83612bf3565b90505b9392505050565b6000670de0b6b3a7640000612a036129da8583615afe565b6129ec90670de0b6b3a7640000615b66565b6129fe85670de0b6b3a7640000615bda565b612c02565b612a0d9086615bda565b6129b89190615afe565b600081831015612a2757816129bb565b5090919050565b6000805a90505b825a612a419083615a5c565b10156127ca57612a5082615e69565b9150612a35565b6000612ab9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612c339092919063ffffffff16565b8051909150156127ca5780806020019051810190612ad791906159da565b6127ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610bd3565b60608180519060200120604051602001612b7f91815260200190565b6040516020818303038152906040529050919050565b6000612bbc84612ba6878686612c42565b8051602091820120825192909101919091201490565b95945050505050565b600080603f83619c4001026040850201603f5a021015949350505050565b600081831215612a2757816129bb565b6000818312612a2757816129bb565b60006129bb670de0b6b3a764000083612c1a866136c0565b612c249190615bda565b612c2e9190615afe565b613904565b60606129b88484600085613b43565b60606000845111612caf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d65726b6c65547269653a20656d707479206b657900000000000000000000006044820152606401610bd3565b6000612cba84613cd9565b90506000612cc786613dc5565b9050600084604051602001612cde91815260200190565b60405160208183030381529060405290506000805b8451811015613637576000858281518110612d1057612d10615ea1565b602002602001015190508451831115612dab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4d65726b6c65547269653a206b657920696e646578206578636565647320746f60448201527f74616c206b6579206c656e6774680000000000000000000000000000000000006064820152608401610bd3565b82600003612e645780518051602091820120604051612df992612dd392910190815260200190565b604051602081830303815290604052858051602091820120825192909101919091201490565b612e5f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f4d65726b6c65547269653a20696e76616c696420726f6f7420686173680000006044820152606401610bd3565b612fbb565b805151602011612f1a5780518051602091820120604051612e8e92612dd392910190815260200190565b612e5f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f4d65726b6c65547269653a20696e76616c6964206c6172676520696e7465726e60448201527f616c2068617368000000000000000000000000000000000000000000000000006064820152608401610bd3565b805184516020808701919091208251919092012014612fbb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4d65726b6c65547269653a20696e76616c696420696e7465726e616c206e6f6460448201527f65206861736800000000000000000000000000000000000000000000000000006064820152608401610bd3565b612fc7601060016157fc565b816020015151036131a3578451830361313b576130018160200151601081518110612ff457612ff4615ea1565b6020026020010151613e28565b96506000875111613094576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603b60248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286272616e63682900000000006064820152608401610bd3565b600186516130a29190615a5c565b8214613130576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286272616e6368290000000000006064820152608401610bd3565b5050505050506129bb565b600085848151811061314f5761314f615ea1565b602001015160f81c60f81b60f81c9050600082602001518260ff168151811061317a5761317a615ea1565b6020026020010151905061318d81613f88565b955061319a6001866157fc565b94505050613624565b60028160200151510361359c5760006131bb82613fad565b90506000816000815181106131d2576131d2615ea1565b016020015160f81c905060006131e9600283615ed0565b6131f4906002615ef2565b90506000613205848360ff16613fd1565b905060006132138a89613fd1565b905060006132218383614007565b9050808351146132b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f4d65726b6c65547269653a20706174682072656d61696e646572206d7573742060448201527f736861726520616c6c206e6962626c65732077697468206b65790000000000006064820152608401610bd3565b60ff8516600214806132c8575060ff85166003145b156134b7578082511461335d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603d60248201527f4d65726b6c65547269653a206b65792072656d61696e646572206d757374206260448201527f65206964656e746963616c20746f20706174682072656d61696e6465720000006064820152608401610bd3565b6133778760200151600181518110612ff457612ff4615ea1565b9c5060008d511161340a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286c65616629000000000000006064820152608401610bd3565b60018c516134189190615a5c565b88146134a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286c6561662900000000000000006064820152608401610bd3565b5050505050505050505050506129bb565b60ff851615806134ca575060ff85166001145b15613509576134f687602001516001815181106134e9576134e9615ea1565b6020026020010151613f88565b9950613502818a6157fc565b9850613591565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4d65726b6c65547269653a2072656365697665642061206e6f6465207769746860448201527f20616e20756e6b6e6f776e2070726566697800000000000000000000000000006064820152608401610bd3565b505050505050613624565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f4d65726b6c65547269653a20726563656976656420616e20756e70617273656160448201527f626c65206e6f64650000000000000000000000000000000000000000000000006064820152608401610bd3565b508061362f81615e69565b915050612cf3565b506040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f4d65726b6c65547269653a2072616e206f7574206f662070726f6f6620656c6560448201527f6d656e74730000000000000000000000000000000000000000000000000000006064820152608401610bd3565b600080821361372b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f554e444546494e454400000000000000000000000000000000000000000000006044820152606401610bd3565b60006060613738846140bb565b03609f8181039490941b90931c6c465772b2bbbb5f824b15207a3081018102606090811d6d0388eaa27412d5aca026815d636e018202811d6d0df99ac502031bf953eff472fdcc018202811d6d13cdffb29d51d99322bdff5f2211018202811d6d0a0f742023def783a307a986912e018202811d6d01920d8043ca89b5239253284e42018202811d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7883018302821d6d0139601a2efabe717e604cbb4894018302821d6d02247f7a7b6594320649aa03aba1018302821d7fffffffffffffffffffffffffffffffffffffff73c0c716a594e00d54e3c4cbc9018302821d7ffffffffffffffffffffffffffffffffffffffdc7b88c420e53a9890533129f6f01830290911d7fffffffffffffffffffffffffffffffffffffff465fda27eb4d63ded474e5f832019091027ffffffffffffffff5f6af8f7b3396644f18e157960000000000000000000000000105711340daa0d5f769dba1915cef59f0815a5506027d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b393909302929092017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d92915050565b60007ffffffffffffffffffffffffffffffffffffffffffffffffdb731c958f34d94c1821361393557506000919050565b680755bf798b4a1bf1e582126139a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4558505f4f564552464c4f5700000000000000000000000000000000000000006044820152606401610bd3565b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b056b80000000000000000000000001901d6bb17217f7d1cf79abc9e3b39881029093037fffffffffffffffffffffffffffffffffffffffdbf3ccf1604d263450f02a550481018102606090811d6d0277594991cfc85f6e2461837cd9018202811d7fffffffffffffffffffffffffffffffffffffe5adedaa1cb095af9e4da10e363c018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d7ffffffffffffffffffffffffffffffffffffd38dc772608b0ae56cce01296c0eb018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084017ffffffffffffffffffffffffffffffffffffffe2c69812cf03b0763fd454a8f7e010290911d6e0587f503bb6ea29d25fcb7401964500190910279d835ebba824c98fb31b83b2ca45c000000000000000000000000010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b606082471015613bd5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610bd3565b73ffffffffffffffffffffffffffffffffffffffff85163b613c53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610bd3565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051613c7c9190615f15565b60006040518083038185875af1925050503d8060008114613cb9576040519150601f19603f3d011682016040523d82523d6000602084013e613cbe565b606091505b5091509150613cce828286614191565b979650505050505050565b80516060908067ffffffffffffffff811115613cf757613cf7615281565b604051908082528060200260200182016040528015613d3c57816020015b6040805180820190915260608082526020820152815260200190600190039081613d155790505b50915060005b81811015613dbe576040518060400160405280858381518110613d6757613d67615ea1565b60200260200101518152602001613d96868481518110613d8957613d89615ea1565b60200260200101516141e4565b815250838281518110613dab57613dab615ea1565b6020908102919091010152600101613d42565b5050919050565b606080604051905082518060011b603f8101601f1916830160405280835250602084016020830160005b83811015613e1d578060011b82018184015160001a8060041c8253600f811660018301535050600101613def565b509295945050505050565b60606000806000613e38856141f7565b919450925090506000816001811115613e5357613e53615f31565b14613ee0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206279746573206973206e6f7420612064617461206974656d000000000000006064820152608401610bd3565b613eea82846157fc565b855114613f79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603460248201527f524c505265616465723a2062797465732076616c756520636f6e7461696e732060448201527f616e20696e76616c69642072656d61696e6465720000000000000000000000006064820152608401610bd3565b612bbc85602001518484614c64565b60606020826000015110613fa457613f9f82613e28565b6110e8565b6110e882614cf8565b60606110e8613fcc8360200151600081518110612ff457612ff4615ea1565b613dc5565b606082518210613ff057506040805160208101909152600081526110e8565b6129bb83838486516140029190615a5c565b614d0e565b600080825184511061401a57825161401d565b83515b90505b80821080156140a4575082828151811061403c5761403c615ea1565b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191684838151811061407b5761407b615ea1565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016145b156140b457816001019150614020565b5092915050565b6000808211614126576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f554e444546494e454400000000000000000000000000000000000000000000006044820152606401610bd3565b5060016fffffffffffffffffffffffffffffffff821160071b82811c67ffffffffffffffff1060061b1782811c63ffffffff1060051b1782811c61ffff1060041b1782811c60ff10600390811b90911783811c600f1060021b1783811c909110821b1791821c111790565b606083156141a05750816129bb565b8251156141b05782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bd39190615613565b60606110e86141f283614ee6565b614fcf565b6000806000808460000151116142b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620616e20524c50206974656d60448201527f206d7573742062652067726561746572207468616e207a65726f20746f20626560648201527f206465636f6461626c6500000000000000000000000000000000000000000000608482015260a401610bd3565b6020840151805160001a607f81116142da576000600160009450945094505050614c5d565b60b781116144e85760006142ef608083615a5c565b9050808760000151116143aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604e60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20737472696e67206c656e6774682060648201527f2873686f727420737472696e6729000000000000000000000000000000000000608482015260a401610bd3565b6001838101517fff0000000000000000000000000000000000000000000000000000000000000016908214158061442357507f80000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000821610155b6144d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604d60248201527f524c505265616465723a20696e76616c6964207072656669782c2073696e676c60448201527f652062797465203c203078383020617265206e6f74207072656669786564202860648201527f73686f727420737472696e672900000000000000000000000000000000000000608482015260a401610bd3565b5060019550935060009250614c5d915050565b60bf81116148365760006144fd60b783615a5c565b9050808760000151116145b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152605160248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206265203e207468616e206c656e677468206f6620737472696e67206c656e60648201527f67746820286c6f6e6720737472696e6729000000000000000000000000000000608482015260a401610bd3565b60018301517fff00000000000000000000000000000000000000000000000000000000000000166000819003614696576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f60648201527f6e6720737472696e672900000000000000000000000000000000000000000000608482015260a401610bd3565b600184015160088302610100031c6037811161475a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604860248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20353520627974657320286c6f6e6760648201527f20737472696e6729000000000000000000000000000000000000000000000000608482015260a401610bd3565b61476481846157fc565b895111614819576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604c60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20746f74616c206c656e677468202860648201527f6c6f6e6720737472696e67290000000000000000000000000000000000000000608482015260a401610bd3565b6148248360016157fc565b9750955060009450614c5d9350505050565b60f7811161491757600061484b60c083615a5c565b905080876000015111614906576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e206c697374206c656e67746820287360648201527f686f7274206c6973742900000000000000000000000000000000000000000000608482015260a401610bd3565b600195509350849250614c5d915050565b600061492460f783615a5c565b9050808760000151116149df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604d60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206265203e207468616e206c656e677468206f66206c697374206c656e677460648201527f6820286c6f6e67206c6973742900000000000000000000000000000000000000608482015260a401610bd3565b60018301517fff00000000000000000000000000000000000000000000000000000000000000166000819003614abd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604860248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f60648201527f6e67206c69737429000000000000000000000000000000000000000000000000608482015260a401610bd3565b600184015160088302610100031c60378111614b81576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604660248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20353520627974657320286c6f6e6760648201527f206c697374290000000000000000000000000000000000000000000000000000608482015260a401610bd3565b614b8b81846157fc565b895111614c40576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620636f6e74656e74206d757360448201527f742062652067726561746572207468616e20746f74616c206c656e677468202860648201527f6c6f6e67206c6973742900000000000000000000000000000000000000000000608482015260a401610bd3565b614c4b8360016157fc565b9750955060019450614c5d9350505050565b9193909250565b60608167ffffffffffffffff811115614c7f57614c7f615281565b6040519080825280601f01601f191660200182016040528015614ca9576020820181803683370190505b50905081156129bb576000614cbe84866157fc565b90506020820160005b84811015614cdf578281015182820152602001614cc7565b84811115614cee576000858301525b5050509392505050565b60606110e8826020015160008460000151614c64565b60608182601f011015614d7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401610bd3565b828284011015614de9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401610bd3565b81830184511015614e56576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f736c6963655f6f75744f66426f756e64730000000000000000000000000000006044820152606401610bd3565b606082158015614e755760405191506000825260208201604052614edd565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015614eae578051835260209283019201614e96565b5050858452601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016604052505b50949350505050565b60408051808201909152600080825260208201526000825111614fb1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f524c505265616465723a206c656e677468206f6620616e20524c50206974656d60448201527f206d7573742062652067726561746572207468616e207a65726f20746f20626560648201527f206465636f6461626c6500000000000000000000000000000000000000000000608482015260a401610bd3565b50604080518082019091528151815260209182019181019190915290565b60606000806000614fdf856141f7565b919450925090506001816001811115614ffa57614ffa615f31565b14615087576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206c697374206973206e6f742061206c697374206974656d00000000000000006064820152608401610bd3565b845161509383856157fc565b14615120576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f524c505265616465723a206c697374206974656d2068617320616e20696e766160448201527f6c696420646174612072656d61696e64657200000000000000000000000000006064820152608401610bd3565b604080516020808252610420820190925290816020015b60408051808201909152600080825260208201528152602001906001900390816151375790505093506000835b8651811015615225576000806151aa6040518060400160405280858c6000015161518e9190615a5c565b8152602001858c602001516151a391906157fc565b90526141f7565b5091509150604051806040016040528083836151c691906157fc565b8152602001848b602001516151db91906157fc565b8152508885815181106151f0576151f0615ea1565b60209081029190910101526152066001856157fc565b935061521281836157fc565b61521c90846157fc565b92505050615164565b50845250919392505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461525357600080fd5b50565b803567ffffffffffffffff8116811461526e57600080fd5b919050565b801515811461525357600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156152f7576152f7615281565b604052919050565b600082601f83011261531057600080fd5b813567ffffffffffffffff81111561532a5761532a615281565b61535b60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016152b0565b81815284602083860101111561537057600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c087890312156153a657600080fd5b86356153b181615231565b955060208701359450604087013593506153cd60608801615256565b925060808701356153dd81615273565b915060a087013567ffffffffffffffff8111156153f957600080fd5b61540589828a016152ff565b9150509295509295509295565b600060c0828403121561542457600080fd5b60405160c0810167ffffffffffffffff828210818311171561544857615448615281565b81604052829350843583526020850135915061546382615231565b8160208401526040850135915061547982615231565b816040840152606085013560608401526080850135608084015260a08501359150808211156154a757600080fd5b506154b4858286016152ff565b60a0830152505092915050565b600080600080600085870360e08112156154da57600080fd5b863567ffffffffffffffff808211156154f257600080fd5b6154fe8a838b01615412565b97506020890135965060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08401121561553757600080fd5b60408901955060c089013592508083111561555157600080fd5b828901925089601f84011261556557600080fd5b823591508082111561557657600080fd5b508860208260051b840101111561558c57600080fd5b959894975092955050506020019190565b60005b838110156155b85781810151838201526020016155a0565b83811115611fed5750506000910152565b600081518084526155e181602086016020860161559d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006129bb60208301846155c9565b60006020828403121561563857600080fd5b5035919050565b60ff8116811461525357600080fd5b6000806000806080858703121561566457600080fd5b843561566f81615231565b9350602085013561567f8161563f565b93969395505050506040820135916060013590565b6000602082840312156156a657600080fd5b813567ffffffffffffffff8111156156bd57600080fd5b6156c984828501615412565b949350505050565b6000602082840312156156e357600080fd5b6129bb82615256565b60008060006060848603121561570157600080fd5b833561570c81615231565b9250602084013561571c81615231565b9150604084013561572c81615231565b809150509250925092565b600080600080600060a0868803121561574f57600080fd5b853561575a81615231565b94506020860135935061576f60408701615256565b9250606086013561577f81615273565b9150608086013567ffffffffffffffff81111561579b57600080fd5b6157a7888289016152ff565b9150509295509295909350565b6000602082840312156157c657600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000821982111561580f5761580f6157cd565b500190565b6000806040838503121561582757600080fd5b825161583281615231565b60208401519092506158438161563f565b809150509250929050565b60006020828403121561586057600080fd5b81516129bb81615231565b80516fffffffffffffffffffffffffffffffff8116811461526e57600080fd5b60006060828403121561589d57600080fd5b6040516060810181811067ffffffffffffffff821117156158c0576158c0615281565b604052825181526158d36020840161586b565b60208201526158e46040840161586b565b60408201529392505050565b60006080828403121561590257600080fd5b6040516080810181811067ffffffffffffffff8211171561592557615925615281565b8060405250823581526020830135602082015260408301356040820152606083013560608201528091505092915050565b600067ffffffffffffffff8084111561597157615971615281565b8360051b60206159828183016152b0565b86815291850191818101903684111561599a57600080fd5b865b848110156159ce578035868111156159b45760008081fd5b6159c036828b016152ff565b84525091830191830161599c565b50979650505050505050565b6000602082840312156159ec57600080fd5b81516129bb81615273565b8581528460208201527fffffffffffffffff0000000000000000000000000000000000000000000000008460c01b16604082015282151560f81b604882015260008251615a4b81604985016020870161559d565b919091016049019695505050505050565b600082821015615a6e57615a6e6157cd565b500390565b600067ffffffffffffffff80831681851681830481118215151615615a9a57615a9a6157cd565b02949350505050565b600067ffffffffffffffff808316818516808303821115615ac657615ac66157cd565b01949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082615b0d57615b0d615acf565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f800000000000000000000000000000000000000000000000000000000000000083141615615b6157615b616157cd565b500590565b6000808312837f800000000000000000000000000000000000000000000000000000000000000001831281151615615ba057615ba06157cd565b837f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff018313811615615bd457615bd46157cd565b50500390565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600084136000841385830485118282161615615c1b57615c1b6157cd565b7f80000000000000000000000000000000000000000000000000000000000000006000871286820588128184161615615c5657615c566157cd565b60008712925087820587128484161615615c7257615c726157cd565b87850587128184161615615c8857615c886157cd565b505050929093029392505050565b6000808212827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03841381151615615cd057615cd06157cd565b827f8000000000000000000000000000000000000000000000000000000000000000038412811615615d0457615d046157cd565b50500190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615615d4257615d426157cd565b500290565b600082615d5657615d56615acf565b500490565b868152600073ffffffffffffffffffffffffffffffffffffffff808816602084015280871660408401525084606083015283608083015260c060a0830152615da660c08301846155c9565b98975050505050505050565b805163ffffffff8116811461526e57600080fd5b600060c08284031215615dd857600080fd5b60405160c0810181811067ffffffffffffffff82111715615dfb57615dfb615281565b604052615e0783615db2565b81526020830151615e178161563f565b60208201526040830151615e2a8161563f565b6040820152615e3b60608401615db2565b6060820152615e4c60808401615db2565b6080820152615e5d60a0840161586b565b60a08201529392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615e9a57615e9a6157cd565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060ff831680615ee357615ee3615acf565b8060ff84160691505092915050565b600060ff821660ff841680821015615f0c57615f0c6157cd565b90039392505050565b60008251615f2781846020870161559d565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea164736f6c634300080f000a", -} - -// OptimismPortalABI is the input ABI used to generate the binding from. -// Deprecated: Use OptimismPortalMetaData.ABI instead. -var OptimismPortalABI = OptimismPortalMetaData.ABI - -// OptimismPortalBin is the compiled bytecode used for deploying new contracts. -// Deprecated: Use OptimismPortalMetaData.Bin instead. -var OptimismPortalBin = OptimismPortalMetaData.Bin - -// DeployOptimismPortal deploys a new Ethereum contract, binding an instance of OptimismPortal to it. -func DeployOptimismPortal(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *OptimismPortal, error) { - parsed, err := OptimismPortalMetaData.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(OptimismPortalBin), backend) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &OptimismPortal{OptimismPortalCaller: OptimismPortalCaller{contract: contract}, OptimismPortalTransactor: OptimismPortalTransactor{contract: contract}, OptimismPortalFilterer: OptimismPortalFilterer{contract: contract}}, nil -} - -// OptimismPortal is an auto generated Go binding around an Ethereum contract. -type OptimismPortal struct { - OptimismPortalCaller // Read-only binding to the contract - OptimismPortalTransactor // Write-only binding to the contract - OptimismPortalFilterer // Log filterer for contract events -} - -// OptimismPortalCaller is an auto generated read-only Go binding around an Ethereum contract. -type OptimismPortalCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// OptimismPortalTransactor is an auto generated write-only Go binding around an Ethereum contract. -type OptimismPortalTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// OptimismPortalFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type OptimismPortalFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// OptimismPortalSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type OptimismPortalSession struct { - Contract *OptimismPortal // 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 -} - -// OptimismPortalCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type OptimismPortalCallerSession struct { - Contract *OptimismPortalCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// OptimismPortalTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type OptimismPortalTransactorSession struct { - Contract *OptimismPortalTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// OptimismPortalRaw is an auto generated low-level Go binding around an Ethereum contract. -type OptimismPortalRaw struct { - Contract *OptimismPortal // Generic contract binding to access the raw methods on -} - -// OptimismPortalCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type OptimismPortalCallerRaw struct { - Contract *OptimismPortalCaller // Generic read-only contract binding to access the raw methods on -} - -// OptimismPortalTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type OptimismPortalTransactorRaw struct { - Contract *OptimismPortalTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewOptimismPortal creates a new instance of OptimismPortal, bound to a specific deployed contract. -func NewOptimismPortal(address common.Address, backend bind.ContractBackend) (*OptimismPortal, error) { - contract, err := bindOptimismPortal(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &OptimismPortal{OptimismPortalCaller: OptimismPortalCaller{contract: contract}, OptimismPortalTransactor: OptimismPortalTransactor{contract: contract}, OptimismPortalFilterer: OptimismPortalFilterer{contract: contract}}, nil -} - -// NewOptimismPortalCaller creates a new read-only instance of OptimismPortal, bound to a specific deployed contract. -func NewOptimismPortalCaller(address common.Address, caller bind.ContractCaller) (*OptimismPortalCaller, error) { - contract, err := bindOptimismPortal(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &OptimismPortalCaller{contract: contract}, nil -} - -// NewOptimismPortalTransactor creates a new write-only instance of OptimismPortal, bound to a specific deployed contract. -func NewOptimismPortalTransactor(address common.Address, transactor bind.ContractTransactor) (*OptimismPortalTransactor, error) { - contract, err := bindOptimismPortal(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &OptimismPortalTransactor{contract: contract}, nil -} - -// NewOptimismPortalFilterer creates a new log filterer instance of OptimismPortal, bound to a specific deployed contract. -func NewOptimismPortalFilterer(address common.Address, filterer bind.ContractFilterer) (*OptimismPortalFilterer, error) { - contract, err := bindOptimismPortal(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &OptimismPortalFilterer{contract: contract}, nil -} - -// bindOptimismPortal binds a generic wrapper to an already deployed contract. -func bindOptimismPortal(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(OptimismPortalABI)) - 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 (_OptimismPortal *OptimismPortalRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _OptimismPortal.Contract.OptimismPortalCaller.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 (_OptimismPortal *OptimismPortalRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _OptimismPortal.Contract.OptimismPortalTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_OptimismPortal *OptimismPortalRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _OptimismPortal.Contract.OptimismPortalTransactor.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 (_OptimismPortal *OptimismPortalCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _OptimismPortal.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 (_OptimismPortal *OptimismPortalTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _OptimismPortal.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_OptimismPortal *OptimismPortalTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _OptimismPortal.Contract.contract.Transact(opts, method, params...) -} - -// Balance is a free data retrieval call binding the contract method 0xb69ef8a8. -// -// Solidity: function balance() view returns(uint256) -func (_OptimismPortal *OptimismPortalCaller) Balance(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _OptimismPortal.contract.Call(opts, &out, "balance") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// Balance is a free data retrieval call binding the contract method 0xb69ef8a8. -// -// Solidity: function balance() view returns(uint256) -func (_OptimismPortal *OptimismPortalSession) Balance() (*big.Int, error) { - return _OptimismPortal.Contract.Balance(&_OptimismPortal.CallOpts) -} - -// Balance is a free data retrieval call binding the contract method 0xb69ef8a8. -// -// Solidity: function balance() view returns(uint256) -func (_OptimismPortal *OptimismPortalCallerSession) Balance() (*big.Int, error) { - return _OptimismPortal.Contract.Balance(&_OptimismPortal.CallOpts) -} - -// FinalizedWithdrawals is a free data retrieval call binding the contract method 0xa14238e7. -// -// Solidity: function finalizedWithdrawals(bytes32 ) view returns(bool) -func (_OptimismPortal *OptimismPortalCaller) FinalizedWithdrawals(opts *bind.CallOpts, arg0 [32]byte) (bool, error) { - var out []interface{} - err := _OptimismPortal.contract.Call(opts, &out, "finalizedWithdrawals", arg0) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// FinalizedWithdrawals is a free data retrieval call binding the contract method 0xa14238e7. -// -// Solidity: function finalizedWithdrawals(bytes32 ) view returns(bool) -func (_OptimismPortal *OptimismPortalSession) FinalizedWithdrawals(arg0 [32]byte) (bool, error) { - return _OptimismPortal.Contract.FinalizedWithdrawals(&_OptimismPortal.CallOpts, arg0) -} - -// FinalizedWithdrawals is a free data retrieval call binding the contract method 0xa14238e7. -// -// Solidity: function finalizedWithdrawals(bytes32 ) view returns(bool) -func (_OptimismPortal *OptimismPortalCallerSession) FinalizedWithdrawals(arg0 [32]byte) (bool, error) { - return _OptimismPortal.Contract.FinalizedWithdrawals(&_OptimismPortal.CallOpts, arg0) -} - -// GasPayingToken is a free data retrieval call binding the contract method 0x4397dfef. -// -// Solidity: function gasPayingToken() view returns(address addr_, uint8 decimals_) -func (_OptimismPortal *OptimismPortalCaller) GasPayingToken(opts *bind.CallOpts) (struct { - Addr common.Address - Decimals uint8 -}, error) { - var out []interface{} - err := _OptimismPortal.contract.Call(opts, &out, "gasPayingToken") - - outstruct := new(struct { - Addr common.Address - Decimals uint8 - }) - if err != nil { - return *outstruct, err - } - - outstruct.Addr = *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - outstruct.Decimals = *abi.ConvertType(out[1], new(uint8)).(*uint8) - - return *outstruct, err - -} - -// GasPayingToken is a free data retrieval call binding the contract method 0x4397dfef. -// -// Solidity: function gasPayingToken() view returns(address addr_, uint8 decimals_) -func (_OptimismPortal *OptimismPortalSession) GasPayingToken() (struct { - Addr common.Address - Decimals uint8 -}, error) { - return _OptimismPortal.Contract.GasPayingToken(&_OptimismPortal.CallOpts) -} - -// GasPayingToken is a free data retrieval call binding the contract method 0x4397dfef. -// -// Solidity: function gasPayingToken() view returns(address addr_, uint8 decimals_) -func (_OptimismPortal *OptimismPortalCallerSession) GasPayingToken() (struct { - Addr common.Address - Decimals uint8 -}, error) { - return _OptimismPortal.Contract.GasPayingToken(&_OptimismPortal.CallOpts) -} - -// Guardian is a free data retrieval call binding the contract method 0x452a9320. -// -// Solidity: function guardian() view returns(address) -func (_OptimismPortal *OptimismPortalCaller) Guardian(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _OptimismPortal.contract.Call(opts, &out, "guardian") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// Guardian is a free data retrieval call binding the contract method 0x452a9320. -// -// Solidity: function guardian() view returns(address) -func (_OptimismPortal *OptimismPortalSession) Guardian() (common.Address, error) { - return _OptimismPortal.Contract.Guardian(&_OptimismPortal.CallOpts) -} - -// Guardian is a free data retrieval call binding the contract method 0x452a9320. -// -// Solidity: function guardian() view returns(address) -func (_OptimismPortal *OptimismPortalCallerSession) Guardian() (common.Address, error) { - return _OptimismPortal.Contract.Guardian(&_OptimismPortal.CallOpts) -} - -// IsOutputFinalized is a free data retrieval call binding the contract method 0x6dbffb78. -// -// Solidity: function isOutputFinalized(uint256 _l2OutputIndex) view returns(bool) -func (_OptimismPortal *OptimismPortalCaller) IsOutputFinalized(opts *bind.CallOpts, _l2OutputIndex *big.Int) (bool, error) { - var out []interface{} - err := _OptimismPortal.contract.Call(opts, &out, "isOutputFinalized", _l2OutputIndex) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// IsOutputFinalized is a free data retrieval call binding the contract method 0x6dbffb78. -// -// Solidity: function isOutputFinalized(uint256 _l2OutputIndex) view returns(bool) -func (_OptimismPortal *OptimismPortalSession) IsOutputFinalized(_l2OutputIndex *big.Int) (bool, error) { - return _OptimismPortal.Contract.IsOutputFinalized(&_OptimismPortal.CallOpts, _l2OutputIndex) -} - -// IsOutputFinalized is a free data retrieval call binding the contract method 0x6dbffb78. -// -// Solidity: function isOutputFinalized(uint256 _l2OutputIndex) view returns(bool) -func (_OptimismPortal *OptimismPortalCallerSession) IsOutputFinalized(_l2OutputIndex *big.Int) (bool, error) { - return _OptimismPortal.Contract.IsOutputFinalized(&_OptimismPortal.CallOpts, _l2OutputIndex) -} - -// L2Oracle is a free data retrieval call binding the contract method 0x9b5f694a. -// -// Solidity: function l2Oracle() view returns(address) -func (_OptimismPortal *OptimismPortalCaller) L2Oracle(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _OptimismPortal.contract.Call(opts, &out, "l2Oracle") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// L2Oracle is a free data retrieval call binding the contract method 0x9b5f694a. -// -// Solidity: function l2Oracle() view returns(address) -func (_OptimismPortal *OptimismPortalSession) L2Oracle() (common.Address, error) { - return _OptimismPortal.Contract.L2Oracle(&_OptimismPortal.CallOpts) -} - -// L2Oracle is a free data retrieval call binding the contract method 0x9b5f694a. -// -// Solidity: function l2Oracle() view returns(address) -func (_OptimismPortal *OptimismPortalCallerSession) L2Oracle() (common.Address, error) { - return _OptimismPortal.Contract.L2Oracle(&_OptimismPortal.CallOpts) -} - -// L2Sender is a free data retrieval call binding the contract method 0x9bf62d82. -// -// Solidity: function l2Sender() view returns(address) -func (_OptimismPortal *OptimismPortalCaller) L2Sender(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _OptimismPortal.contract.Call(opts, &out, "l2Sender") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// L2Sender is a free data retrieval call binding the contract method 0x9bf62d82. -// -// Solidity: function l2Sender() view returns(address) -func (_OptimismPortal *OptimismPortalSession) L2Sender() (common.Address, error) { - return _OptimismPortal.Contract.L2Sender(&_OptimismPortal.CallOpts) -} - -// L2Sender is a free data retrieval call binding the contract method 0x9bf62d82. -// -// Solidity: function l2Sender() view returns(address) -func (_OptimismPortal *OptimismPortalCallerSession) L2Sender() (common.Address, error) { - return _OptimismPortal.Contract.L2Sender(&_OptimismPortal.CallOpts) -} - -// MinimumGasLimit is a free data retrieval call binding the contract method 0xa35d99df. -// -// Solidity: function minimumGasLimit(uint64 _byteCount) pure returns(uint64) -func (_OptimismPortal *OptimismPortalCaller) MinimumGasLimit(opts *bind.CallOpts, _byteCount uint64) (uint64, error) { - var out []interface{} - err := _OptimismPortal.contract.Call(opts, &out, "minimumGasLimit", _byteCount) - - if err != nil { - return *new(uint64), err - } - - out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) - - return out0, err - -} - -// MinimumGasLimit is a free data retrieval call binding the contract method 0xa35d99df. -// -// Solidity: function minimumGasLimit(uint64 _byteCount) pure returns(uint64) -func (_OptimismPortal *OptimismPortalSession) MinimumGasLimit(_byteCount uint64) (uint64, error) { - return _OptimismPortal.Contract.MinimumGasLimit(&_OptimismPortal.CallOpts, _byteCount) -} - -// MinimumGasLimit is a free data retrieval call binding the contract method 0xa35d99df. -// -// Solidity: function minimumGasLimit(uint64 _byteCount) pure returns(uint64) -func (_OptimismPortal *OptimismPortalCallerSession) MinimumGasLimit(_byteCount uint64) (uint64, error) { - return _OptimismPortal.Contract.MinimumGasLimit(&_OptimismPortal.CallOpts, _byteCount) -} - -// Params is a free data retrieval call binding the contract method 0xcff0ab96. -// -// Solidity: function params() view returns(uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) -func (_OptimismPortal *OptimismPortalCaller) Params(opts *bind.CallOpts) (struct { - PrevBaseFee *big.Int - PrevBoughtGas uint64 - PrevBlockNum uint64 -}, error) { - var out []interface{} - err := _OptimismPortal.contract.Call(opts, &out, "params") - - outstruct := new(struct { - PrevBaseFee *big.Int - PrevBoughtGas uint64 - PrevBlockNum uint64 - }) - if err != nil { - return *outstruct, err - } - - outstruct.PrevBaseFee = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - outstruct.PrevBoughtGas = *abi.ConvertType(out[1], new(uint64)).(*uint64) - outstruct.PrevBlockNum = *abi.ConvertType(out[2], new(uint64)).(*uint64) - - return *outstruct, err - -} - -// Params is a free data retrieval call binding the contract method 0xcff0ab96. -// -// Solidity: function params() view returns(uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) -func (_OptimismPortal *OptimismPortalSession) Params() (struct { - PrevBaseFee *big.Int - PrevBoughtGas uint64 - PrevBlockNum uint64 -}, error) { - return _OptimismPortal.Contract.Params(&_OptimismPortal.CallOpts) -} - -// Params is a free data retrieval call binding the contract method 0xcff0ab96. -// -// Solidity: function params() view returns(uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) -func (_OptimismPortal *OptimismPortalCallerSession) Params() (struct { - PrevBaseFee *big.Int - PrevBoughtGas uint64 - PrevBlockNum uint64 -}, error) { - return _OptimismPortal.Contract.Params(&_OptimismPortal.CallOpts) -} - -// Paused is a free data retrieval call binding the contract method 0x5c975abb. -// -// Solidity: function paused() view returns(bool paused_) -func (_OptimismPortal *OptimismPortalCaller) Paused(opts *bind.CallOpts) (bool, error) { - var out []interface{} - err := _OptimismPortal.contract.Call(opts, &out, "paused") - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// Paused is a free data retrieval call binding the contract method 0x5c975abb. -// -// Solidity: function paused() view returns(bool paused_) -func (_OptimismPortal *OptimismPortalSession) Paused() (bool, error) { - return _OptimismPortal.Contract.Paused(&_OptimismPortal.CallOpts) -} - -// Paused is a free data retrieval call binding the contract method 0x5c975abb. -// -// Solidity: function paused() view returns(bool paused_) -func (_OptimismPortal *OptimismPortalCallerSession) Paused() (bool, error) { - return _OptimismPortal.Contract.Paused(&_OptimismPortal.CallOpts) -} - -// ProvenWithdrawals is a free data retrieval call binding the contract method 0xe965084c. -// -// Solidity: function provenWithdrawals(bytes32 ) view returns(bytes32 outputRoot, uint128 timestamp, uint128 l2OutputIndex) -func (_OptimismPortal *OptimismPortalCaller) ProvenWithdrawals(opts *bind.CallOpts, arg0 [32]byte) (struct { - OutputRoot [32]byte - Timestamp *big.Int - L2OutputIndex *big.Int -}, error) { - var out []interface{} - err := _OptimismPortal.contract.Call(opts, &out, "provenWithdrawals", arg0) - - outstruct := new(struct { - OutputRoot [32]byte - Timestamp *big.Int - L2OutputIndex *big.Int - }) - if err != nil { - return *outstruct, err - } - - outstruct.OutputRoot = *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) - outstruct.Timestamp = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) - outstruct.L2OutputIndex = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) - - return *outstruct, err - -} - -// ProvenWithdrawals is a free data retrieval call binding the contract method 0xe965084c. -// -// Solidity: function provenWithdrawals(bytes32 ) view returns(bytes32 outputRoot, uint128 timestamp, uint128 l2OutputIndex) -func (_OptimismPortal *OptimismPortalSession) ProvenWithdrawals(arg0 [32]byte) (struct { - OutputRoot [32]byte - Timestamp *big.Int - L2OutputIndex *big.Int -}, error) { - return _OptimismPortal.Contract.ProvenWithdrawals(&_OptimismPortal.CallOpts, arg0) -} - -// ProvenWithdrawals is a free data retrieval call binding the contract method 0xe965084c. -// -// Solidity: function provenWithdrawals(bytes32 ) view returns(bytes32 outputRoot, uint128 timestamp, uint128 l2OutputIndex) -func (_OptimismPortal *OptimismPortalCallerSession) ProvenWithdrawals(arg0 [32]byte) (struct { - OutputRoot [32]byte - Timestamp *big.Int - L2OutputIndex *big.Int -}, error) { - return _OptimismPortal.Contract.ProvenWithdrawals(&_OptimismPortal.CallOpts, arg0) -} - -// SuperchainConfig is a free data retrieval call binding the contract method 0x35e80ab3. -// -// Solidity: function superchainConfig() view returns(address) -func (_OptimismPortal *OptimismPortalCaller) SuperchainConfig(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _OptimismPortal.contract.Call(opts, &out, "superchainConfig") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// SuperchainConfig is a free data retrieval call binding the contract method 0x35e80ab3. -// -// Solidity: function superchainConfig() view returns(address) -func (_OptimismPortal *OptimismPortalSession) SuperchainConfig() (common.Address, error) { - return _OptimismPortal.Contract.SuperchainConfig(&_OptimismPortal.CallOpts) -} - -// SuperchainConfig is a free data retrieval call binding the contract method 0x35e80ab3. -// -// Solidity: function superchainConfig() view returns(address) -func (_OptimismPortal *OptimismPortalCallerSession) SuperchainConfig() (common.Address, error) { - return _OptimismPortal.Contract.SuperchainConfig(&_OptimismPortal.CallOpts) -} - -// SystemConfig is a free data retrieval call binding the contract method 0x33d7e2bd. -// -// Solidity: function systemConfig() view returns(address) -func (_OptimismPortal *OptimismPortalCaller) SystemConfig(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _OptimismPortal.contract.Call(opts, &out, "systemConfig") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// SystemConfig is a free data retrieval call binding the contract method 0x33d7e2bd. -// -// Solidity: function systemConfig() view returns(address) -func (_OptimismPortal *OptimismPortalSession) SystemConfig() (common.Address, error) { - return _OptimismPortal.Contract.SystemConfig(&_OptimismPortal.CallOpts) -} - -// SystemConfig is a free data retrieval call binding the contract method 0x33d7e2bd. -// -// Solidity: function systemConfig() view returns(address) -func (_OptimismPortal *OptimismPortalCallerSession) SystemConfig() (common.Address, error) { - return _OptimismPortal.Contract.SystemConfig(&_OptimismPortal.CallOpts) -} - -// Version is a free data retrieval call binding the contract method 0x54fd4d50. -// -// Solidity: function version() view returns(string) -func (_OptimismPortal *OptimismPortalCaller) Version(opts *bind.CallOpts) (string, error) { - var out []interface{} - err := _OptimismPortal.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 (_OptimismPortal *OptimismPortalSession) Version() (string, error) { - return _OptimismPortal.Contract.Version(&_OptimismPortal.CallOpts) -} - -// Version is a free data retrieval call binding the contract method 0x54fd4d50. -// -// Solidity: function version() view returns(string) -func (_OptimismPortal *OptimismPortalCallerSession) Version() (string, error) { - return _OptimismPortal.Contract.Version(&_OptimismPortal.CallOpts) -} - -// DepositERC20Transaction is a paid mutator transaction binding the contract method 0x149f2f22. -// -// Solidity: function depositERC20Transaction(address _to, uint256 _mint, uint256 _value, uint64 _gasLimit, bool _isCreation, bytes _data) returns() -func (_OptimismPortal *OptimismPortalTransactor) DepositERC20Transaction(opts *bind.TransactOpts, _to common.Address, _mint *big.Int, _value *big.Int, _gasLimit uint64, _isCreation bool, _data []byte) (*types.Transaction, error) { - return _OptimismPortal.contract.Transact(opts, "depositERC20Transaction", _to, _mint, _value, _gasLimit, _isCreation, _data) -} - -// DepositERC20Transaction is a paid mutator transaction binding the contract method 0x149f2f22. -// -// Solidity: function depositERC20Transaction(address _to, uint256 _mint, uint256 _value, uint64 _gasLimit, bool _isCreation, bytes _data) returns() -func (_OptimismPortal *OptimismPortalSession) DepositERC20Transaction(_to common.Address, _mint *big.Int, _value *big.Int, _gasLimit uint64, _isCreation bool, _data []byte) (*types.Transaction, error) { - return _OptimismPortal.Contract.DepositERC20Transaction(&_OptimismPortal.TransactOpts, _to, _mint, _value, _gasLimit, _isCreation, _data) -} - -// DepositERC20Transaction is a paid mutator transaction binding the contract method 0x149f2f22. -// -// Solidity: function depositERC20Transaction(address _to, uint256 _mint, uint256 _value, uint64 _gasLimit, bool _isCreation, bytes _data) returns() -func (_OptimismPortal *OptimismPortalTransactorSession) DepositERC20Transaction(_to common.Address, _mint *big.Int, _value *big.Int, _gasLimit uint64, _isCreation bool, _data []byte) (*types.Transaction, error) { - return _OptimismPortal.Contract.DepositERC20Transaction(&_OptimismPortal.TransactOpts, _to, _mint, _value, _gasLimit, _isCreation, _data) -} - -// DepositTransaction is a paid mutator transaction binding the contract method 0xe9e05c42. -// -// Solidity: function depositTransaction(address _to, uint256 _value, uint64 _gasLimit, bool _isCreation, bytes _data) payable returns() -func (_OptimismPortal *OptimismPortalTransactor) DepositTransaction(opts *bind.TransactOpts, _to common.Address, _value *big.Int, _gasLimit uint64, _isCreation bool, _data []byte) (*types.Transaction, error) { - return _OptimismPortal.contract.Transact(opts, "depositTransaction", _to, _value, _gasLimit, _isCreation, _data) -} - -// DepositTransaction is a paid mutator transaction binding the contract method 0xe9e05c42. -// -// Solidity: function depositTransaction(address _to, uint256 _value, uint64 _gasLimit, bool _isCreation, bytes _data) payable returns() -func (_OptimismPortal *OptimismPortalSession) DepositTransaction(_to common.Address, _value *big.Int, _gasLimit uint64, _isCreation bool, _data []byte) (*types.Transaction, error) { - return _OptimismPortal.Contract.DepositTransaction(&_OptimismPortal.TransactOpts, _to, _value, _gasLimit, _isCreation, _data) -} - -// DepositTransaction is a paid mutator transaction binding the contract method 0xe9e05c42. -// -// Solidity: function depositTransaction(address _to, uint256 _value, uint64 _gasLimit, bool _isCreation, bytes _data) payable returns() -func (_OptimismPortal *OptimismPortalTransactorSession) DepositTransaction(_to common.Address, _value *big.Int, _gasLimit uint64, _isCreation bool, _data []byte) (*types.Transaction, error) { - return _OptimismPortal.Contract.DepositTransaction(&_OptimismPortal.TransactOpts, _to, _value, _gasLimit, _isCreation, _data) -} - -// DonateETH is a paid mutator transaction binding the contract method 0x8b4c40b0. -// -// Solidity: function donateETH() payable returns() -func (_OptimismPortal *OptimismPortalTransactor) DonateETH(opts *bind.TransactOpts) (*types.Transaction, error) { - return _OptimismPortal.contract.Transact(opts, "donateETH") -} - -// DonateETH is a paid mutator transaction binding the contract method 0x8b4c40b0. -// -// Solidity: function donateETH() payable returns() -func (_OptimismPortal *OptimismPortalSession) DonateETH() (*types.Transaction, error) { - return _OptimismPortal.Contract.DonateETH(&_OptimismPortal.TransactOpts) -} - -// DonateETH is a paid mutator transaction binding the contract method 0x8b4c40b0. -// -// Solidity: function donateETH() payable returns() -func (_OptimismPortal *OptimismPortalTransactorSession) DonateETH() (*types.Transaction, error) { - return _OptimismPortal.Contract.DonateETH(&_OptimismPortal.TransactOpts) -} - -// FinalizeWithdrawalTransaction is a paid mutator transaction binding the contract method 0x8c3152e9. -// -// Solidity: function finalizeWithdrawalTransaction((uint256,address,address,uint256,uint256,bytes) _tx) returns() -func (_OptimismPortal *OptimismPortalTransactor) FinalizeWithdrawalTransaction(opts *bind.TransactOpts, _tx TypesWithdrawalTransaction) (*types.Transaction, error) { - return _OptimismPortal.contract.Transact(opts, "finalizeWithdrawalTransaction", _tx) -} - -// FinalizeWithdrawalTransaction is a paid mutator transaction binding the contract method 0x8c3152e9. -// -// Solidity: function finalizeWithdrawalTransaction((uint256,address,address,uint256,uint256,bytes) _tx) returns() -func (_OptimismPortal *OptimismPortalSession) FinalizeWithdrawalTransaction(_tx TypesWithdrawalTransaction) (*types.Transaction, error) { - return _OptimismPortal.Contract.FinalizeWithdrawalTransaction(&_OptimismPortal.TransactOpts, _tx) -} - -// FinalizeWithdrawalTransaction is a paid mutator transaction binding the contract method 0x8c3152e9. -// -// Solidity: function finalizeWithdrawalTransaction((uint256,address,address,uint256,uint256,bytes) _tx) returns() -func (_OptimismPortal *OptimismPortalTransactorSession) FinalizeWithdrawalTransaction(_tx TypesWithdrawalTransaction) (*types.Transaction, error) { - return _OptimismPortal.Contract.FinalizeWithdrawalTransaction(&_OptimismPortal.TransactOpts, _tx) -} - -// Initialize is a paid mutator transaction binding the contract method 0xc0c53b8b. -// -// Solidity: function initialize(address _l2Oracle, address _systemConfig, address _superchainConfig) returns() -func (_OptimismPortal *OptimismPortalTransactor) Initialize(opts *bind.TransactOpts, _l2Oracle common.Address, _systemConfig common.Address, _superchainConfig common.Address) (*types.Transaction, error) { - return _OptimismPortal.contract.Transact(opts, "initialize", _l2Oracle, _systemConfig, _superchainConfig) -} - -// Initialize is a paid mutator transaction binding the contract method 0xc0c53b8b. -// -// Solidity: function initialize(address _l2Oracle, address _systemConfig, address _superchainConfig) returns() -func (_OptimismPortal *OptimismPortalSession) Initialize(_l2Oracle common.Address, _systemConfig common.Address, _superchainConfig common.Address) (*types.Transaction, error) { - return _OptimismPortal.Contract.Initialize(&_OptimismPortal.TransactOpts, _l2Oracle, _systemConfig, _superchainConfig) -} - -// Initialize is a paid mutator transaction binding the contract method 0xc0c53b8b. -// -// Solidity: function initialize(address _l2Oracle, address _systemConfig, address _superchainConfig) returns() -func (_OptimismPortal *OptimismPortalTransactorSession) Initialize(_l2Oracle common.Address, _systemConfig common.Address, _superchainConfig common.Address) (*types.Transaction, error) { - return _OptimismPortal.Contract.Initialize(&_OptimismPortal.TransactOpts, _l2Oracle, _systemConfig, _superchainConfig) -} - -// ProveWithdrawalTransaction is a paid mutator transaction binding the contract method 0x4870496f. -// -// Solidity: function proveWithdrawalTransaction((uint256,address,address,uint256,uint256,bytes) _tx, uint256 _l2OutputIndex, (bytes32,bytes32,bytes32,bytes32) _outputRootProof, bytes[] _withdrawalProof) returns() -func (_OptimismPortal *OptimismPortalTransactor) ProveWithdrawalTransaction(opts *bind.TransactOpts, _tx TypesWithdrawalTransaction, _l2OutputIndex *big.Int, _outputRootProof TypesOutputRootProof, _withdrawalProof [][]byte) (*types.Transaction, error) { - return _OptimismPortal.contract.Transact(opts, "proveWithdrawalTransaction", _tx, _l2OutputIndex, _outputRootProof, _withdrawalProof) -} - -// ProveWithdrawalTransaction is a paid mutator transaction binding the contract method 0x4870496f. -// -// Solidity: function proveWithdrawalTransaction((uint256,address,address,uint256,uint256,bytes) _tx, uint256 _l2OutputIndex, (bytes32,bytes32,bytes32,bytes32) _outputRootProof, bytes[] _withdrawalProof) returns() -func (_OptimismPortal *OptimismPortalSession) ProveWithdrawalTransaction(_tx TypesWithdrawalTransaction, _l2OutputIndex *big.Int, _outputRootProof TypesOutputRootProof, _withdrawalProof [][]byte) (*types.Transaction, error) { - return _OptimismPortal.Contract.ProveWithdrawalTransaction(&_OptimismPortal.TransactOpts, _tx, _l2OutputIndex, _outputRootProof, _withdrawalProof) -} - -// ProveWithdrawalTransaction is a paid mutator transaction binding the contract method 0x4870496f. -// -// Solidity: function proveWithdrawalTransaction((uint256,address,address,uint256,uint256,bytes) _tx, uint256 _l2OutputIndex, (bytes32,bytes32,bytes32,bytes32) _outputRootProof, bytes[] _withdrawalProof) returns() -func (_OptimismPortal *OptimismPortalTransactorSession) ProveWithdrawalTransaction(_tx TypesWithdrawalTransaction, _l2OutputIndex *big.Int, _outputRootProof TypesOutputRootProof, _withdrawalProof [][]byte) (*types.Transaction, error) { - return _OptimismPortal.Contract.ProveWithdrawalTransaction(&_OptimismPortal.TransactOpts, _tx, _l2OutputIndex, _outputRootProof, _withdrawalProof) -} - -// SetGasPayingToken is a paid mutator transaction binding the contract method 0x71cfaa3f. -// -// Solidity: function setGasPayingToken(address _token, uint8 _decimals, bytes32 _name, bytes32 _symbol) returns() -func (_OptimismPortal *OptimismPortalTransactor) SetGasPayingToken(opts *bind.TransactOpts, _token common.Address, _decimals uint8, _name [32]byte, _symbol [32]byte) (*types.Transaction, error) { - return _OptimismPortal.contract.Transact(opts, "setGasPayingToken", _token, _decimals, _name, _symbol) -} - -// SetGasPayingToken is a paid mutator transaction binding the contract method 0x71cfaa3f. -// -// Solidity: function setGasPayingToken(address _token, uint8 _decimals, bytes32 _name, bytes32 _symbol) returns() -func (_OptimismPortal *OptimismPortalSession) SetGasPayingToken(_token common.Address, _decimals uint8, _name [32]byte, _symbol [32]byte) (*types.Transaction, error) { - return _OptimismPortal.Contract.SetGasPayingToken(&_OptimismPortal.TransactOpts, _token, _decimals, _name, _symbol) -} - -// SetGasPayingToken is a paid mutator transaction binding the contract method 0x71cfaa3f. -// -// Solidity: function setGasPayingToken(address _token, uint8 _decimals, bytes32 _name, bytes32 _symbol) returns() -func (_OptimismPortal *OptimismPortalTransactorSession) SetGasPayingToken(_token common.Address, _decimals uint8, _name [32]byte, _symbol [32]byte) (*types.Transaction, error) { - return _OptimismPortal.Contract.SetGasPayingToken(&_OptimismPortal.TransactOpts, _token, _decimals, _name, _symbol) -} - -// Receive is a paid mutator transaction binding the contract receive function. -// -// Solidity: receive() payable returns() -func (_OptimismPortal *OptimismPortalTransactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) { - return _OptimismPortal.contract.RawTransact(opts, nil) // calldata is disallowed for receive function -} - -// Receive is a paid mutator transaction binding the contract receive function. -// -// Solidity: receive() payable returns() -func (_OptimismPortal *OptimismPortalSession) Receive() (*types.Transaction, error) { - return _OptimismPortal.Contract.Receive(&_OptimismPortal.TransactOpts) -} - -// Receive is a paid mutator transaction binding the contract receive function. -// -// Solidity: receive() payable returns() -func (_OptimismPortal *OptimismPortalTransactorSession) Receive() (*types.Transaction, error) { - return _OptimismPortal.Contract.Receive(&_OptimismPortal.TransactOpts) -} - -// OptimismPortalInitializedIterator is returned from FilterInitialized and is used to iterate over the raw logs and unpacked data for Initialized events raised by the OptimismPortal contract. -type OptimismPortalInitializedIterator struct { - Event *OptimismPortalInitialized // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *OptimismPortalInitializedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(OptimismPortalInitialized) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(OptimismPortalInitialized) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *OptimismPortalInitializedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *OptimismPortalInitializedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// OptimismPortalInitialized represents a Initialized event raised by the OptimismPortal contract. -type OptimismPortalInitialized struct { - Version uint8 - Raw types.Log // Blockchain specific contextual infos -} - -// FilterInitialized is a free log retrieval operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. -// -// Solidity: event Initialized(uint8 version) -func (_OptimismPortal *OptimismPortalFilterer) FilterInitialized(opts *bind.FilterOpts) (*OptimismPortalInitializedIterator, error) { - - logs, sub, err := _OptimismPortal.contract.FilterLogs(opts, "Initialized") - if err != nil { - return nil, err - } - return &OptimismPortalInitializedIterator{contract: _OptimismPortal.contract, event: "Initialized", logs: logs, sub: sub}, nil -} - -// WatchInitialized is a free log subscription operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. -// -// Solidity: event Initialized(uint8 version) -func (_OptimismPortal *OptimismPortalFilterer) WatchInitialized(opts *bind.WatchOpts, sink chan<- *OptimismPortalInitialized) (event.Subscription, error) { - - logs, sub, err := _OptimismPortal.contract.WatchLogs(opts, "Initialized") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(OptimismPortalInitialized) - if err := _OptimismPortal.contract.UnpackLog(event, "Initialized", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseInitialized is a log parse operation binding the contract event 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498. -// -// Solidity: event Initialized(uint8 version) -func (_OptimismPortal *OptimismPortalFilterer) ParseInitialized(log types.Log) (*OptimismPortalInitialized, error) { - event := new(OptimismPortalInitialized) - if err := _OptimismPortal.contract.UnpackLog(event, "Initialized", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// OptimismPortalTransactionDepositedIterator is returned from FilterTransactionDeposited and is used to iterate over the raw logs and unpacked data for TransactionDeposited events raised by the OptimismPortal contract. -type OptimismPortalTransactionDepositedIterator struct { - Event *OptimismPortalTransactionDeposited // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *OptimismPortalTransactionDepositedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(OptimismPortalTransactionDeposited) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(OptimismPortalTransactionDeposited) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *OptimismPortalTransactionDepositedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *OptimismPortalTransactionDepositedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// OptimismPortalTransactionDeposited represents a TransactionDeposited event raised by the OptimismPortal contract. -type OptimismPortalTransactionDeposited struct { - From common.Address - To common.Address - Version *big.Int - OpaqueData []byte - Raw types.Log // Blockchain specific contextual infos -} - -// FilterTransactionDeposited is a free log retrieval operation binding the contract event 0xb3813568d9991fc951961fcb4c784893574240a28925604d09fc577c55bb7c32. -// -// Solidity: event TransactionDeposited(address indexed from, address indexed to, uint256 indexed version, bytes opaqueData) -func (_OptimismPortal *OptimismPortalFilterer) FilterTransactionDeposited(opts *bind.FilterOpts, from []common.Address, to []common.Address, version []*big.Int) (*OptimismPortalTransactionDepositedIterator, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - var versionRule []interface{} - for _, versionItem := range version { - versionRule = append(versionRule, versionItem) - } - - logs, sub, err := _OptimismPortal.contract.FilterLogs(opts, "TransactionDeposited", fromRule, toRule, versionRule) - if err != nil { - return nil, err - } - return &OptimismPortalTransactionDepositedIterator{contract: _OptimismPortal.contract, event: "TransactionDeposited", logs: logs, sub: sub}, nil -} - -// WatchTransactionDeposited is a free log subscription operation binding the contract event 0xb3813568d9991fc951961fcb4c784893574240a28925604d09fc577c55bb7c32. -// -// Solidity: event TransactionDeposited(address indexed from, address indexed to, uint256 indexed version, bytes opaqueData) -func (_OptimismPortal *OptimismPortalFilterer) WatchTransactionDeposited(opts *bind.WatchOpts, sink chan<- *OptimismPortalTransactionDeposited, from []common.Address, to []common.Address, version []*big.Int) (event.Subscription, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - var versionRule []interface{} - for _, versionItem := range version { - versionRule = append(versionRule, versionItem) - } - - logs, sub, err := _OptimismPortal.contract.WatchLogs(opts, "TransactionDeposited", fromRule, toRule, versionRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(OptimismPortalTransactionDeposited) - if err := _OptimismPortal.contract.UnpackLog(event, "TransactionDeposited", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseTransactionDeposited is a log parse operation binding the contract event 0xb3813568d9991fc951961fcb4c784893574240a28925604d09fc577c55bb7c32. -// -// Solidity: event TransactionDeposited(address indexed from, address indexed to, uint256 indexed version, bytes opaqueData) -func (_OptimismPortal *OptimismPortalFilterer) ParseTransactionDeposited(log types.Log) (*OptimismPortalTransactionDeposited, error) { - event := new(OptimismPortalTransactionDeposited) - if err := _OptimismPortal.contract.UnpackLog(event, "TransactionDeposited", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// OptimismPortalWithdrawalFinalizedIterator is returned from FilterWithdrawalFinalized and is used to iterate over the raw logs and unpacked data for WithdrawalFinalized events raised by the OptimismPortal contract. -type OptimismPortalWithdrawalFinalizedIterator struct { - Event *OptimismPortalWithdrawalFinalized // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *OptimismPortalWithdrawalFinalizedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(OptimismPortalWithdrawalFinalized) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(OptimismPortalWithdrawalFinalized) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *OptimismPortalWithdrawalFinalizedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *OptimismPortalWithdrawalFinalizedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// OptimismPortalWithdrawalFinalized represents a WithdrawalFinalized event raised by the OptimismPortal contract. -type OptimismPortalWithdrawalFinalized struct { - WithdrawalHash [32]byte - Success bool - Raw types.Log // Blockchain specific contextual infos -} - -// FilterWithdrawalFinalized is a free log retrieval operation binding the contract event 0xdb5c7652857aa163daadd670e116628fb42e869d8ac4251ef8971d9e5727df1b. -// -// Solidity: event WithdrawalFinalized(bytes32 indexed withdrawalHash, bool success) -func (_OptimismPortal *OptimismPortalFilterer) FilterWithdrawalFinalized(opts *bind.FilterOpts, withdrawalHash [][32]byte) (*OptimismPortalWithdrawalFinalizedIterator, error) { - - var withdrawalHashRule []interface{} - for _, withdrawalHashItem := range withdrawalHash { - withdrawalHashRule = append(withdrawalHashRule, withdrawalHashItem) - } - - logs, sub, err := _OptimismPortal.contract.FilterLogs(opts, "WithdrawalFinalized", withdrawalHashRule) - if err != nil { - return nil, err - } - return &OptimismPortalWithdrawalFinalizedIterator{contract: _OptimismPortal.contract, event: "WithdrawalFinalized", logs: logs, sub: sub}, nil -} - -// WatchWithdrawalFinalized is a free log subscription operation binding the contract event 0xdb5c7652857aa163daadd670e116628fb42e869d8ac4251ef8971d9e5727df1b. -// -// Solidity: event WithdrawalFinalized(bytes32 indexed withdrawalHash, bool success) -func (_OptimismPortal *OptimismPortalFilterer) WatchWithdrawalFinalized(opts *bind.WatchOpts, sink chan<- *OptimismPortalWithdrawalFinalized, withdrawalHash [][32]byte) (event.Subscription, error) { - - var withdrawalHashRule []interface{} - for _, withdrawalHashItem := range withdrawalHash { - withdrawalHashRule = append(withdrawalHashRule, withdrawalHashItem) - } - - logs, sub, err := _OptimismPortal.contract.WatchLogs(opts, "WithdrawalFinalized", withdrawalHashRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(OptimismPortalWithdrawalFinalized) - if err := _OptimismPortal.contract.UnpackLog(event, "WithdrawalFinalized", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseWithdrawalFinalized is a log parse operation binding the contract event 0xdb5c7652857aa163daadd670e116628fb42e869d8ac4251ef8971d9e5727df1b. -// -// Solidity: event WithdrawalFinalized(bytes32 indexed withdrawalHash, bool success) -func (_OptimismPortal *OptimismPortalFilterer) ParseWithdrawalFinalized(log types.Log) (*OptimismPortalWithdrawalFinalized, error) { - event := new(OptimismPortalWithdrawalFinalized) - if err := _OptimismPortal.contract.UnpackLog(event, "WithdrawalFinalized", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// OptimismPortalWithdrawalProvenIterator is returned from FilterWithdrawalProven and is used to iterate over the raw logs and unpacked data for WithdrawalProven events raised by the OptimismPortal contract. -type OptimismPortalWithdrawalProvenIterator struct { - Event *OptimismPortalWithdrawalProven // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *OptimismPortalWithdrawalProvenIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(OptimismPortalWithdrawalProven) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(OptimismPortalWithdrawalProven) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *OptimismPortalWithdrawalProvenIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *OptimismPortalWithdrawalProvenIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// OptimismPortalWithdrawalProven represents a WithdrawalProven event raised by the OptimismPortal contract. -type OptimismPortalWithdrawalProven struct { - WithdrawalHash [32]byte - From common.Address - To common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterWithdrawalProven is a free log retrieval operation binding the contract event 0x67a6208cfcc0801d50f6cbe764733f4fddf66ac0b04442061a8a8c0cb6b63f62. -// -// Solidity: event WithdrawalProven(bytes32 indexed withdrawalHash, address indexed from, address indexed to) -func (_OptimismPortal *OptimismPortalFilterer) FilterWithdrawalProven(opts *bind.FilterOpts, withdrawalHash [][32]byte, from []common.Address, to []common.Address) (*OptimismPortalWithdrawalProvenIterator, error) { - - var withdrawalHashRule []interface{} - for _, withdrawalHashItem := range withdrawalHash { - withdrawalHashRule = append(withdrawalHashRule, withdrawalHashItem) - } - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _OptimismPortal.contract.FilterLogs(opts, "WithdrawalProven", withdrawalHashRule, fromRule, toRule) - if err != nil { - return nil, err - } - return &OptimismPortalWithdrawalProvenIterator{contract: _OptimismPortal.contract, event: "WithdrawalProven", logs: logs, sub: sub}, nil -} - -// WatchWithdrawalProven is a free log subscription operation binding the contract event 0x67a6208cfcc0801d50f6cbe764733f4fddf66ac0b04442061a8a8c0cb6b63f62. -// -// Solidity: event WithdrawalProven(bytes32 indexed withdrawalHash, address indexed from, address indexed to) -func (_OptimismPortal *OptimismPortalFilterer) WatchWithdrawalProven(opts *bind.WatchOpts, sink chan<- *OptimismPortalWithdrawalProven, withdrawalHash [][32]byte, from []common.Address, to []common.Address) (event.Subscription, error) { - - var withdrawalHashRule []interface{} - for _, withdrawalHashItem := range withdrawalHash { - withdrawalHashRule = append(withdrawalHashRule, withdrawalHashItem) - } - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _OptimismPortal.contract.WatchLogs(opts, "WithdrawalProven", withdrawalHashRule, fromRule, toRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(OptimismPortalWithdrawalProven) - if err := _OptimismPortal.contract.UnpackLog(event, "WithdrawalProven", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseWithdrawalProven is a log parse operation binding the contract event 0x67a6208cfcc0801d50f6cbe764733f4fddf66ac0b04442061a8a8c0cb6b63f62. -// -// Solidity: event WithdrawalProven(bytes32 indexed withdrawalHash, address indexed from, address indexed to) -func (_OptimismPortal *OptimismPortalFilterer) ParseWithdrawalProven(log types.Log) (*OptimismPortalWithdrawalProven, error) { - event := new(OptimismPortalWithdrawalProven) - if err := _OptimismPortal.contract.UnpackLog(event, "WithdrawalProven", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} diff --git a/op-dispute-mon/mon/extract/caller_test.go b/op-dispute-mon/mon/extract/caller_test.go index 12f8941bcc3fd..b7d6a432ee451 100644 --- a/op-dispute-mon/mon/extract/caller_test.go +++ b/op-dispute-mon/mon/extract/caller_test.go @@ -7,11 +7,11 @@ import ( contractMetrics "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics" "github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock" + "github.com/ethereum-optimism/optimism/packages/contracts-bedrock/snapshots" "github.com/ethereum/go-ethereum/common" faultTypes "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types" "github.com/ethereum-optimism/optimism/op-challenger/game/types" - "github.com/ethereum-optimism/optimism/op-dispute-mon/bindings" "github.com/ethereum-optimism/optimism/op-service/sources/batching" batchingTest "github.com/ethereum-optimism/optimism/op-service/sources/batching/test" "github.com/stretchr/testify/require" @@ -68,8 +68,7 @@ func TestMetadataCreator_CreateContract(t *testing.T) { } func setupMetadataLoaderTest(t *testing.T) (*batching.MultiCaller, *mockCacheMetrics) { - fdgAbi, err := bindings.FaultDisputeGameMetaData.GetAbi() - require.NoError(t, err) + fdgAbi := snapshots.LoadFaultDisputeGameABI() stubRpc := batchingTest.NewAbiBasedRpc(t, fdgAddr, fdgAbi) caller := batching.NewMultiCaller(stubRpc, batching.DefaultBatchSize) stubRpc.SetResponse(fdgAddr, "version", rpcblock.Latest, nil, []interface{}{"0.18.0"}) diff --git a/op-e2e/actions/l1_replica.go b/op-e2e/actions/l1_replica.go index 92796ab60fb00..430dffa3920d1 100644 --- a/op-e2e/actions/l1_replica.go +++ b/op-e2e/actions/l1_replica.go @@ -3,6 +3,8 @@ package actions import ( "errors" + "github.com/stretchr/testify/require" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/txpool/blobpool" "github.com/ethereum/go-ethereum/core/types" @@ -14,7 +16,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" - "github.com/stretchr/testify/require" + "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/client" @@ -43,7 +45,7 @@ type L1Replica struct { l1Cfg *core.Genesis l1Signer types.Signer - failL1RPC func() error // mock error + failL1RPC func(call []rpc.BatchElem) error // mock error } // NewL1Replica constructs a L1Replica starting at the given genesis. @@ -152,18 +154,16 @@ func (s *L1Replica) CanonL1Chain() func(num uint64) *types.Block { // ActL1RPCFail makes the next L1 RPC request to this node fail func (s *L1Replica) ActL1RPCFail(t Testing) { - failed := false - s.failL1RPC = func() error { - if failed { - return nil - } - failed = true + s.failL1RPC = func(call []rpc.BatchElem) error { + s.failL1RPC = nil return errors.New("mock L1 RPC error") } } func (s *L1Replica) MockL1RPCErrors(fn func() error) { - s.failL1RPC = fn + s.failL1RPC = func(call []rpc.BatchElem) error { + return fn() + } } func (s *L1Replica) EthClient() *ethclient.Client { @@ -175,12 +175,11 @@ func (s *L1Replica) RPCClient() client.RPC { cl := s.node.Attach() return testutils.RPCErrFaker{ RPC: client.NewBaseRPCClient(cl), - ErrFn: func() error { - if s.failL1RPC != nil { - return s.failL1RPC() - } else { + ErrFn: func(call []rpc.BatchElem) error { + if s.failL1RPC == nil { return nil } + return s.failL1RPC(call) }, } } diff --git a/op-e2e/actions/l2_engine.go b/op-e2e/actions/l2_engine.go index 910f487fb7c0a..88d40ec2a3b95 100644 --- a/op-e2e/actions/l2_engine.go +++ b/op-e2e/actions/l2_engine.go @@ -44,7 +44,7 @@ type L2Engine struct { engineApi *engineapi.L2EngineAPI - failL2RPC error // mock error + failL2RPC func(call []rpc.BatchElem) error // mock error } type EngineOption func(ethCfg *ethconfig.Config, nodeCfg *node.Config) error @@ -160,10 +160,11 @@ func (e *L2Engine) RPCClient() client.RPC { cl := e.node.Attach() return testutils.RPCErrFaker{ RPC: client.NewBaseRPCClient(cl), - ErrFn: func() error { - err := e.failL2RPC - e.failL2RPC = nil // reset back, only error once. - return err + ErrFn: func(call []rpc.BatchElem) error { + if e.failL2RPC == nil { + return nil + } + return e.failL2RPC(call) }, } } @@ -180,7 +181,10 @@ func (e *L2Engine) ActL2RPCFail(t Testing, err error) { t.InvalidAction("already set a mock L2 rpc error") return } - e.failL2RPC = err + e.failL2RPC = func(call []rpc.BatchElem) error { + e.failL2RPC = nil + return err + } } // ActL2IncludeTx includes the next transaction from the given address in the block that is being built diff --git a/op-e2e/actions/l2_sequencer.go b/op-e2e/actions/l2_sequencer.go index 23993b557f153..afa54e2ea75c6 100644 --- a/op-e2e/actions/l2_sequencer.go +++ b/op-e2e/actions/l2_sequencer.go @@ -2,28 +2,31 @@ package actions import ( "context" - "errors" "github.com/stretchr/testify/require" + "golang.org/x/time/rate" "github.com/ethereum/go-ethereum/log" "github.com/ethereum-optimism/optimism/op-node/metrics" + "github.com/ethereum-optimism/optimism/op-node/node" "github.com/ethereum-optimism/optimism/op-node/node/safedb" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup/async" "github.com/ethereum-optimism/optimism/op-node/rollup/conductor" + "github.com/ethereum-optimism/optimism/op-node/rollup/confdepth" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-node/rollup/driver" "github.com/ethereum-optimism/optimism/op-node/rollup/engine" "github.com/ethereum-optimism/optimism/op-node/rollup/event" + "github.com/ethereum-optimism/optimism/op-node/rollup/sequencing" "github.com/ethereum-optimism/optimism/op-node/rollup/sync" "github.com/ethereum-optimism/optimism/op-service/eth" ) // MockL1OriginSelector is a shim to override the origin as sequencer, so we can force it to stay on an older origin. type MockL1OriginSelector struct { - actual *driver.L1OriginSelector + actual *sequencing.L1OriginSelector originOverride eth.L1BlockRef // override which origin gets picked } @@ -39,7 +42,7 @@ func (m *MockL1OriginSelector) FindL1Origin(ctx context.Context, l2Head eth.L2Bl type L2Sequencer struct { *L2Verifier - sequencer *driver.Sequencer + sequencer *sequencing.Sequencer failL2GossipUnsafeBlock error // mock error @@ -50,13 +53,33 @@ func NewL2Sequencer(t Testing, log log.Logger, l1 derive.L1Fetcher, blobSrc deri plasmaSrc driver.PlasmaIface, eng L2API, cfg *rollup.Config, seqConfDepth uint64) *L2Sequencer { ver := NewL2Verifier(t, log, l1, blobSrc, plasmaSrc, eng, cfg, &sync.Config{}, safedb.Disabled) attrBuilder := derive.NewFetchingAttributesBuilder(cfg, l1, eng) - seqConfDepthL1 := driver.NewConfDepth(seqConfDepth, ver.syncStatus.L1Head, l1) + seqConfDepthL1 := confdepth.NewConfDepth(seqConfDepth, ver.syncStatus.L1Head, l1) l1OriginSelector := &MockL1OriginSelector{ - actual: driver.NewL1OriginSelector(log, cfg, seqConfDepthL1), - } + actual: sequencing.NewL1OriginSelector(log, cfg, seqConfDepthL1), + } + metr := metrics.NoopMetrics + seqStateListener := node.DisabledConfigPersistence{} + conduc := &conductor.NoOpConductor{} + asyncGossip := async.NoOpGossiper{} + seq := sequencing.NewSequencer(t.Ctx(), log, cfg, attrBuilder, l1OriginSelector, + seqStateListener, conduc, asyncGossip, metr) + opts := event.DefaultRegisterOpts() + opts.Emitter = event.EmitterOpts{ + Limiting: true, + // TestSyncBatchType/DerivationWithFlakyL1RPC does *a lot* of quick retries + // TestL2BatcherBatchType/ExtendedTimeWithoutL1Batches as well. + Rate: rate.Limit(100_000), + Burst: 100_000, + OnLimited: func() { + log.Warn("Hitting events rate-limit. An events code-path may be hot-looping.") + t.Fatal("Tests must not hot-loop events") + }, + } + ver.eventSys.Register("sequencer", seq, opts) + require.NoError(t, seq.Init(t.Ctx(), true)) return &L2Sequencer{ L2Verifier: ver, - sequencer: driver.NewSequencer(log, cfg, ver.engine, attrBuilder, l1OriginSelector, metrics.NoopMetrics), + sequencer: seq, mockL1OriginSelector: l1OriginSelector, failL2GossipUnsafeBlock: nil, } @@ -64,10 +87,6 @@ func NewL2Sequencer(t Testing, log log.Logger, l1 derive.L1Fetcher, blobSrc deri // ActL2StartBlock starts building of a new L2 block on top of the head func (s *L2Sequencer) ActL2StartBlock(t Testing) { - s.ActL2StartBlockCheckErr(t, nil) -} - -func (s *L2Sequencer) ActL2StartBlockCheckErr(t Testing, checkErr error) { if !s.l2PipelineIdle { t.InvalidAction("cannot start L2 build when derivation is not idle") return @@ -76,21 +95,11 @@ func (s *L2Sequencer) ActL2StartBlockCheckErr(t Testing, checkErr error) { t.InvalidAction("already started building L2 block") return } + s.synchronousEvents.Emit(sequencing.SequencerActionEvent{}) + require.NoError(t, s.drainer.DrainUntil(event.Is[engine.BuildStartedEvent], false), + "failed to start block building") - err := s.sequencer.StartBuildingBlock(t.Ctx()) - if checkErr == nil { - require.NoError(t, err, "failed to start block building") - } else { - require.ErrorIs(t, err, checkErr, "expected typed error") - } - - if errors.Is(err, derive.ErrReset) { - s.derivation.Reset() - } - - if err == nil { - s.l2Building = true - } + s.l2Building = true } // ActL2EndBlock completes a new L2 block and applies it to the L2 chain as new canonical unsafe head @@ -101,16 +110,15 @@ func (s *L2Sequencer) ActL2EndBlock(t Testing) { } s.l2Building = false - _, err := s.sequencer.CompleteBuildingBlock(t.Ctx(), async.NoOpGossiper{}, &conductor.NoOpConductor{}) - // TODO: there may be legitimate temporary errors here, if we mock engine API RPC-failure. - // For advanced tests we can catch those and print a warning instead. - require.NoError(t, err) + s.synchronousEvents.Emit(sequencing.SequencerActionEvent{}) + require.NoError(t, s.drainer.DrainUntil(event.Is[engine.PayloadSuccessEvent], false), + "failed to complete block building") // After having built a L2 block, make sure to get an engine update processed. // This will ensure the sync-status and such reflect the latest changes. s.synchronousEvents.Emit(engine.TryUpdateEngineEvent{}) s.synchronousEvents.Emit(engine.ForkchoiceRequestEvent{}) - require.NoError(t, s.synchronousEvents.DrainUntil(func(ev event.Event) bool { + require.NoError(t, s.drainer.DrainUntil(func(ev event.Event) bool { x, ok := ev.(engine.ForkchoiceUpdateEvent) return ok && x.UnsafeL2Head == s.engine.UnsafeL2Head() }, false)) diff --git a/op-e2e/actions/l2_sequencer_test.go b/op-e2e/actions/l2_sequencer_test.go index 352533cf26186..0786e780d369e 100644 --- a/op-e2e/actions/l2_sequencer_test.go +++ b/op-e2e/actions/l2_sequencer_test.go @@ -40,15 +40,15 @@ func EngineWithP2P() EngineOption { func setupSequencerTest(t Testing, sd *e2eutils.SetupData, log log.Logger) (*L1Miner, *L2Engine, *L2Sequencer) { jwtPath := e2eutils.WriteDefaultJWT(t) - miner := NewL1Miner(t, log, sd.L1Cfg) + miner := NewL1Miner(t, log.New("role", "l1-miner"), sd.L1Cfg) l1F, err := sources.NewL1Client(miner.RPCClient(), log, nil, sources.L1ClientDefaultConfig(sd.RollupCfg, false, sources.RPCKindStandard)) require.NoError(t, err) - engine := NewL2Engine(t, log, sd.L2Cfg, sd.RollupCfg.Genesis.L1, jwtPath, EngineWithP2P()) + engine := NewL2Engine(t, log.New("role", "sequencer-engine"), sd.L2Cfg, sd.RollupCfg.Genesis.L1, jwtPath, EngineWithP2P()) l2Cl, err := sources.NewEngineClient(engine.RPCClient(), log, nil, sources.EngineClientDefaultConfig(sd.RollupCfg)) require.NoError(t, err) - sequencer := NewL2Sequencer(t, log, l1F, miner.BlobStore(), plasma.Disabled, l2Cl, sd.RollupCfg, 0) + sequencer := NewL2Sequencer(t, log.New("role", "sequencer"), l1F, miner.BlobStore(), plasma.Disabled, l2Cl, sd.RollupCfg, 0) return miner, engine, sequencer } diff --git a/op-e2e/actions/l2_verifier.go b/op-e2e/actions/l2_verifier.go index 5039a0ec79fe3..f94083ef0576f 100644 --- a/op-e2e/actions/l2_verifier.go +++ b/op-e2e/actions/l2_verifier.go @@ -35,23 +35,23 @@ import ( // L2Verifier is an actor that functions like a rollup node, // without the full P2P/API/Node stack, but just the derivation state, and simplified driver. type L2Verifier struct { + eventSys event.System + log log.Logger eng L2API syncStatus driver.SyncStatusTracker - synchronousEvents event.EmitterDrainer + synchronousEvents event.Emitter - syncDeriver *driver.SyncDeriver + drainer event.Drainer // L2 rollup engine *engine.EngineController derivation *derive.DerivationPipeline - clSync *clsync.CLSync safeHeadListener rollup.SafeHeadListener - finalizer driver.Finalizer syncCfg *sync.Config l1 derive.L1Fetcher @@ -63,7 +63,7 @@ type L2Verifier struct { rpc *rpc.Server - failRPC error // mock error + failRPC func(call []rpc.BatchElem) error // mock error // The L2Verifier actor is embedded in the L2Sequencer actor, // but must not be copied for the deriver-functionality to modify the same state. @@ -88,37 +88,53 @@ func NewL2Verifier(t Testing, log log.Logger, l1 derive.L1Fetcher, blobsSrc deri ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(cancel) - rootDeriver := &event.DeriverMux{} - var synchronousEvents event.EmitterDrainer - synchronousEvents = event.NewQueue(log, ctx, rootDeriver, event.NoopMetrics{}) - synchronousEvents = event.NewLimiterDrainer(ctx, synchronousEvents, rate.Limit(1000), 20, func() { - log.Warn("Hitting events rate-limit. An events code-path may be hot-looping.") - t.Fatal("Tests must not hot-loop events") - }) + executor := event.NewGlobalSynchronous(ctx) + sys := event.NewSystem(log, executor) + t.Cleanup(sys.Stop) + opts := event.DefaultRegisterOpts() + opts.Emitter = event.EmitterOpts{ + Limiting: true, + // TestSyncBatchType/DerivationWithFlakyL1RPC does *a lot* of quick retries + // TestL2BatcherBatchType/ExtendedTimeWithoutL1Batches as well. + Rate: rate.Limit(100_000), + Burst: 100_000, + OnLimited: func() { + log.Warn("Hitting events rate-limit. An events code-path may be hot-looping.") + t.Fatal("Tests must not hot-loop events") + }, + } metrics := &testutils.TestDerivationMetrics{} - ec := engine.NewEngineController(eng, log, metrics, cfg, syncCfg, synchronousEvents) - engineResetDeriver := engine.NewEngineResetDeriver(ctx, log, cfg, l1, eng, syncCfg, synchronousEvents) + ec := engine.NewEngineController(eng, log, metrics, cfg, syncCfg, + sys.Register("engine-controller", nil, opts)) + + sys.Register("engine-reset", + engine.NewEngineResetDeriver(ctx, log, cfg, l1, eng, syncCfg), opts) - clSync := clsync.NewCLSync(log, cfg, metrics, synchronousEvents) + clSync := clsync.NewCLSync(log, cfg, metrics) + sys.Register("cl-sync", clSync, opts) var finalizer driver.Finalizer if cfg.PlasmaEnabled() { - finalizer = finality.NewPlasmaFinalizer(ctx, log, cfg, l1, synchronousEvents, plasmaSrc) + finalizer = finality.NewPlasmaFinalizer(ctx, log, cfg, l1, plasmaSrc) } else { - finalizer = finality.NewFinalizer(ctx, log, cfg, l1, synchronousEvents) + finalizer = finality.NewFinalizer(ctx, log, cfg, l1) } + sys.Register("finalizer", finalizer, opts) - attributesHandler := attributes.NewAttributesHandler(log, cfg, ctx, eng, synchronousEvents) + sys.Register("attributes-handler", + attributes.NewAttributesHandler(log, cfg, ctx, eng), opts) pipeline := derive.NewDerivationPipeline(log, cfg, l1, blobsSrc, plasmaSrc, eng, metrics) - pipelineDeriver := derive.NewPipelineDeriver(ctx, pipeline, synchronousEvents) + sys.Register("pipeline", derive.NewPipelineDeriver(ctx, pipeline), opts) + + testActionEmitter := sys.Register("test-action", nil, opts) syncStatusTracker := status.NewStatusTracker(log, metrics) + sys.Register("status", syncStatusTracker, opts) - syncDeriver := &driver.SyncDeriver{ + sys.Register("sync", &driver.SyncDeriver{ Derivation: pipeline, - Finalizer: finalizer, SafeHeadNotifs: safeHeadListener, CLSync: clSync, Engine: ec, @@ -126,44 +142,31 @@ func NewL2Verifier(t Testing, log log.Logger, l1 derive.L1Fetcher, blobsSrc deri Config: cfg, L1: l1, L2: eng, - Emitter: synchronousEvents, Log: log, Ctx: ctx, - Drain: synchronousEvents.Drain, - } + Drain: executor.Drain, + }, opts) - engDeriv := engine.NewEngDeriver(log, ctx, cfg, ec, synchronousEvents) + sys.Register("engine", engine.NewEngDeriver(log, ctx, cfg, metrics, ec), opts) rollupNode := &L2Verifier{ + eventSys: sys, log: log, eng: eng, engine: ec, - clSync: clSync, derivation: pipeline, - finalizer: finalizer, safeHeadListener: safeHeadListener, syncCfg: syncCfg, - syncDeriver: syncDeriver, + drainer: executor, l1: l1, syncStatus: syncStatusTracker, l2PipelineIdle: true, l2Building: false, rollupCfg: cfg, rpc: rpc.NewServer(), - synchronousEvents: synchronousEvents, - } - - *rootDeriver = event.DeriverMux{ - syncStatusTracker, - syncDeriver, - engineResetDeriver, - engDeriv, - rollupNode, - clSync, - pipelineDeriver, - attributesHandler, - finalizer, + synchronousEvents: testActionEmitter, } + sys.Register("verifier", rollupNode, opts) t.Cleanup(rollupNode.rpc.Stop) @@ -259,10 +262,11 @@ func (s *L2Verifier) RPCClient() client.RPC { cl := rpc.DialInProc(s.rpc) return testutils.RPCErrFaker{ RPC: client.NewBaseRPCClient(cl), - ErrFn: func() error { - err := s.failRPC - s.failRPC = nil // reset back, only error once. - return err + ErrFn: func(call []rpc.BatchElem) error { + if s.failRPC == nil { + return nil + } + return s.failRPC(call) }, } } @@ -273,14 +277,17 @@ func (s *L2Verifier) ActRPCFail(t Testing) { t.InvalidAction("already set a mock rpc error") return } - s.failRPC = errors.New("mock RPC error") + s.failRPC = func(call []rpc.BatchElem) error { + s.failRPC = nil + return errors.New("mock RPC error") + } } func (s *L2Verifier) ActL1HeadSignal(t Testing) { head, err := s.l1.L1BlockRefByLabel(t.Ctx(), eth.Unsafe) require.NoError(t, err) s.synchronousEvents.Emit(status.L1UnsafeEvent{L1Unsafe: head}) - require.NoError(t, s.synchronousEvents.DrainUntil(func(ev event.Event) bool { + require.NoError(t, s.drainer.DrainUntil(func(ev event.Event) bool { x, ok := ev.(status.L1UnsafeEvent) return ok && x.L1Unsafe == head }, false)) @@ -291,7 +298,7 @@ func (s *L2Verifier) ActL1SafeSignal(t Testing) { safe, err := s.l1.L1BlockRefByLabel(t.Ctx(), eth.Safe) require.NoError(t, err) s.synchronousEvents.Emit(status.L1SafeEvent{L1Safe: safe}) - require.NoError(t, s.synchronousEvents.DrainUntil(func(ev event.Event) bool { + require.NoError(t, s.drainer.DrainUntil(func(ev event.Event) bool { x, ok := ev.(status.L1SafeEvent) return ok && x.L1Safe == safe }, false)) @@ -302,14 +309,14 @@ func (s *L2Verifier) ActL1FinalizedSignal(t Testing) { finalized, err := s.l1.L1BlockRefByLabel(t.Ctx(), eth.Finalized) require.NoError(t, err) s.synchronousEvents.Emit(finality.FinalizeL1Event{FinalizedL1: finalized}) - require.NoError(t, s.synchronousEvents.DrainUntil(func(ev event.Event) bool { + require.NoError(t, s.drainer.DrainUntil(func(ev event.Event) bool { x, ok := ev.(finality.FinalizeL1Event) return ok && x.FinalizedL1 == finalized }, false)) require.Equal(t, finalized, s.syncStatus.SyncStatus().FinalizedL1) } -func (s *L2Verifier) OnEvent(ev event.Event) { +func (s *L2Verifier) OnEvent(ev event.Event) bool { switch x := ev.(type) { case rollup.L1TemporaryErrorEvent: s.log.Warn("L1 temporary error", "err", x.Err) @@ -324,7 +331,14 @@ func (s *L2Verifier) OnEvent(ev event.Event) { panic(fmt.Errorf("derivation failed critically: %w", x.Err)) case derive.DeriverIdleEvent: s.l2PipelineIdle = true + case derive.PipelineStepEvent: + s.l2PipelineIdle = false + case driver.StepReqEvent: + s.synchronousEvents.Emit(driver.StepEvent{}) + default: + return false } + return true } func (s *L2Verifier) ActL2EventsUntilPending(t Testing, num uint64) { @@ -341,7 +355,7 @@ func (s *L2Verifier) ActL2EventsUntil(t Testing, fn func(ev event.Event) bool, m return } for i := 0; i < max; i++ { - err := s.synchronousEvents.DrainUntil(fn, excl) + err := s.drainer.DrainUntil(fn, excl) if err == nil { return } @@ -353,23 +367,8 @@ func (s *L2Verifier) ActL2EventsUntil(t Testing, fn func(ev event.Event) bool, m } func (s *L2Verifier) ActL2PipelineFull(t Testing) { - s.l2PipelineIdle = false - i := 0 - for !s.l2PipelineIdle { - i += 1 - // Some tests do generate a lot of derivation steps - // (e.g. thousand blocks span-batch, or deep reorgs). - // Hence we set the sanity limit to something really high. - if i > 10_000 { - t.Fatalf("ActL2PipelineFull running for too long. Is a deriver looping?") - } - if s.l2Building { - t.InvalidAction("cannot derive new data while building L2 block") - return - } - s.syncDeriver.Emitter.Emit(driver.StepEvent{}) - require.NoError(t, s.syncDeriver.Drain(), "complete all event processing triggered by deriver step") - } + s.synchronousEvents.Emit(driver.StepEvent{}) + require.NoError(t, s.drainer.Drain(), "complete all event processing triggered by deriver step") } // ActL2UnsafeGossipReceive creates an action that can receive an unsafe execution payload, like gossipsub diff --git a/op-e2e/actions/l2_verifier_test.go b/op-e2e/actions/l2_verifier_test.go index 6fe70a3e6fb42..01a2ba0c1eb01 100644 --- a/op-e2e/actions/l2_verifier_test.go +++ b/op-e2e/actions/l2_verifier_test.go @@ -39,9 +39,9 @@ func setupVerifier(t Testing, sd *e2eutils.SetupData, log log.Logger, l1F derive opt(cfg) } jwtPath := e2eutils.WriteDefaultJWT(t) - engine := NewL2Engine(t, log, sd.L2Cfg, sd.RollupCfg.Genesis.L1, jwtPath, EngineWithP2P()) + engine := NewL2Engine(t, log.New("role", "verifier-engine"), sd.L2Cfg, sd.RollupCfg.Genesis.L1, jwtPath, EngineWithP2P()) engCl := engine.EngineClient(t, sd.RollupCfg) - verifier := NewL2Verifier(t, log, l1F, blobSrc, plasma.Disabled, engCl, sd.RollupCfg, syncCfg, cfg.safeHeadListener) + verifier := NewL2Verifier(t, log.New("role", "verifier"), l1F, blobSrc, plasma.Disabled, engCl, sd.RollupCfg, syncCfg, cfg.safeHeadListener) return engine, verifier } diff --git a/op-e2e/actions/sync_test.go b/op-e2e/actions/sync_test.go index f9917d10e8b56..1b9cb61d2c374 100644 --- a/op-e2e/actions/sync_test.go +++ b/op-e2e/actions/sync_test.go @@ -4,6 +4,7 @@ import ( "errors" "math/big" "math/rand" + "strings" "testing" "time" @@ -16,9 +17,9 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" engine2 "github.com/ethereum-optimism/optimism/op-node/rollup/engine" "github.com/ethereum-optimism/optimism/op-node/rollup/event" @@ -448,7 +449,7 @@ func TestBackupUnsafeReorgForkChoiceInputError(gt *testing.T) { // B3 is invalid block // NextAttributes is called - sequencer.ActL2EventsUntil(t, event.Is[engine2.ProcessAttributesEvent], 100, true) + sequencer.ActL2EventsUntil(t, event.Is[engine2.BuildStartEvent], 100, true) // mock forkChoiceUpdate error while restoring previous unsafe chain using backupUnsafe. seqEng.ActL2RPCFail(t, eth.InputError{Inner: errors.New("mock L2 RPC error"), Code: eth.InvalidForkchoiceState}) @@ -581,17 +582,28 @@ func TestBackupUnsafeReorgForkChoiceNotInputError(gt *testing.T) { // B3 is invalid block // wait till attributes processing (excl.) before mocking errors - sequencer.ActL2EventsUntil(t, event.Is[engine2.ProcessAttributesEvent], 100, true) + sequencer.ActL2EventsUntil(t, event.Is[engine2.BuildStartEvent], 100, true) serverErrCnt := 2 - for i := 0; i < serverErrCnt; i++ { - // mock forkChoiceUpdate failure while restoring previous unsafe chain using backupUnsafe. - seqEng.ActL2RPCFail(t, gethengine.GenericServerError) - // TryBackupUnsafeReorg is called - forkChoiceUpdate returns GenericServerError so retry - sequencer.ActL2EventsUntil(t, event.Is[rollup.EngineTemporaryErrorEvent], 100, false) - // backupUnsafeHead not emptied yet - require.Equal(t, targetUnsafeHeadHash, sequencer.L2BackupUnsafe().Hash) + // mock forkChoiceUpdate failure while restoring previous unsafe chain using backupUnsafe. + seqEng.failL2RPC = func(call []rpc.BatchElem) error { + for _, e := range call { + // There may be other calls, like payload-processing-cancellation + // based on previous invalid block, and processing of block attributes. + if strings.HasPrefix(e.Method, "engine_forkchoiceUpdated") && e.Args[1].(*eth.PayloadAttributes) == nil { + if serverErrCnt > 0 { + serverErrCnt -= 1 + return gethengine.GenericServerError + } else { + return nil + } + } + } + return nil } + // cannot drain events until specific engine error, since SyncDeriver calls Drain internally still. + sequencer.ActL2PipelineFull(t) + // now forkchoice succeeds // try to process invalid leftovers: B4, B5 sequencer.ActL2PipelineFull(t) diff --git a/op-e2e/sequencer_failover_test.go b/op-e2e/sequencer_failover_test.go index 0fa38f54ba3c7..f8f5534ecea00 100644 --- a/op-e2e/sequencer_failover_test.go +++ b/op-e2e/sequencer_failover_test.go @@ -211,7 +211,7 @@ func TestSequencerFailover_DisasterRecovery_OverrideLeader(t *testing.T) { // Start sequencer without the overrideLeader flag set to true, should fail err = sys.RollupClient(Sequencer3Name).StartSequencer(ctx, common.Hash{1, 2, 3}) - require.ErrorContains(t, err, "sequencer is not the leader, aborting.", "Expected sequencer to fail to start") + require.ErrorContains(t, err, "sequencer is not the leader, aborting", "Expected sequencer to fail to start") // Start sequencer with the overrideLeader flag set to true, should succeed err = sys.RollupClient(Sequencer3Name).OverrideLeader(ctx) diff --git a/op-node/metrics/metrics.go b/op-node/metrics/metrics.go index ce9c06ab1aa59..2f6c643206af2 100644 --- a/op-node/metrics/metrics.go +++ b/op-node/metrics/metrics.go @@ -39,8 +39,8 @@ type Metricer interface { RecordSequencingError() RecordPublishingError() RecordDerivationError() - RecordEmittedEvent(name string) - RecordProcessedEvent(name string) + RecordEmittedEvent(eventName string, emitter string) + RecordProcessedEvent(eventName string, deriver string, duration time.Duration) RecordEventsRateLimited() RecordReceivedUnsafePayload(payload *eth.ExecutionPayloadEnvelope) RecordRef(layer string, name string, num uint64, timestamp uint64, h common.Hash) @@ -98,6 +98,13 @@ type Metrics struct { EmittedEvents *prometheus.CounterVec ProcessedEvents *prometheus.CounterVec + // We don't use a histogram for observing time durations, + // as each vec entry (event-type, deriver type) is synchronous with other occurrences of the same entry key, + // so we can get a reasonably good understanding of execution by looking at the rate. + // Bucketing to detect outliers would be nice, but also increases the overhead by a lot, + // where we already track many event-type/deriver combinations. + EventsProcessTime *prometheus.CounterVec + EventsRateLimited *metrics.Event DerivedBatches metrics.EventVec @@ -209,7 +216,7 @@ func NewMetrics(procName string) *Metrics { Subsystem: "events", Name: "emitted", Help: "number of emitted events", - }, []string{"event_type"}), + }, []string{"event_type", "emitter"}), ProcessedEvents: factory.NewCounterVec( prometheus.CounterOpts{ @@ -217,7 +224,15 @@ func NewMetrics(procName string) *Metrics { Subsystem: "events", Name: "processed", Help: "number of processed events", - }, []string{"event_type"}), + }, []string{"event_type", "deriver"}), + + EventsProcessTime: factory.NewCounterVec( + prometheus.CounterOpts{ + Namespace: ns, + Subsystem: "events", + Name: "process_time", + Help: "total duration in seconds of processed events", + }, []string{"event_type", "deriver"}), EventsRateLimited: metrics.NewEvent(factory, ns, "events", "rate_limited", "events rate limiter hits"), @@ -467,12 +482,15 @@ func (m *Metrics) RecordPublishingError() { m.PublishingErrors.Record() } -func (m *Metrics) RecordEmittedEvent(name string) { - m.EmittedEvents.WithLabelValues(name).Inc() +func (m *Metrics) RecordEmittedEvent(eventName string, emitter string) { + m.EmittedEvents.WithLabelValues(eventName, emitter).Inc() } -func (m *Metrics) RecordProcessedEvent(name string) { - m.ProcessedEvents.WithLabelValues(name).Inc() +func (m *Metrics) RecordProcessedEvent(eventName string, deriver string, duration time.Duration) { + m.ProcessedEvents.WithLabelValues(eventName, deriver).Inc() + // We take the absolute value; if the clock was not monotonically increased between start and top, + // there still was a duration gap. And the Counter metrics-type would panic if the duration is negative. + m.EventsProcessTime.WithLabelValues(eventName, deriver).Add(float64(duration.Abs()) / float64(time.Second)) } func (m *Metrics) RecordEventsRateLimited() { @@ -680,10 +698,10 @@ func (n *noopMetricer) RecordPublishingError() { func (n *noopMetricer) RecordDerivationError() { } -func (n *noopMetricer) RecordEmittedEvent(name string) { +func (n *noopMetricer) RecordEmittedEvent(eventName string, emitter string) { } -func (n *noopMetricer) RecordProcessedEvent(name string) { +func (n *noopMetricer) RecordProcessedEvent(eventName string, deriver string, duration time.Duration) { } func (n *noopMetricer) RecordEventsRateLimited() { diff --git a/op-node/p2p/config.go b/op-node/p2p/config.go index 433421f26302f..94b75a95de263 100644 --- a/op-node/p2p/config.go +++ b/op-node/p2p/config.go @@ -13,7 +13,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/netutil" ds "github.com/ipfs/go-datastore" - "github.com/libp2p/go-libp2p" + libp2p "github.com/libp2p/go-libp2p" pubsub "github.com/libp2p/go-libp2p-pubsub" "github.com/libp2p/go-libp2p/core" "github.com/libp2p/go-libp2p/core/connmgr" diff --git a/op-node/p2p/host_test.go b/op-node/p2p/host_test.go index 3fcfb7714c26e..2bab3239e55e5 100644 --- a/op-node/p2p/host_test.go +++ b/op-node/p2p/host_test.go @@ -11,7 +11,7 @@ import ( ds "github.com/ipfs/go-datastore" "github.com/ipfs/go-datastore/sync" - "github.com/libp2p/go-libp2p" + libp2p "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" diff --git a/op-node/rollup/attributes/attributes.go b/op-node/rollup/attributes/attributes.go index 116e3c4aba0dc..4ebb27050882b 100644 --- a/op-node/rollup/attributes/attributes.go +++ b/op-node/rollup/attributes/attributes.go @@ -34,21 +34,25 @@ type AttributesHandler struct { emitter event.Emitter - attributes *derive.AttributesWithParent + attributes *derive.AttributesWithParent + sentAttributes bool } -func NewAttributesHandler(log log.Logger, cfg *rollup.Config, ctx context.Context, l2 L2, emitter event.Emitter) *AttributesHandler { +func NewAttributesHandler(log log.Logger, cfg *rollup.Config, ctx context.Context, l2 L2) *AttributesHandler { return &AttributesHandler{ log: log, cfg: cfg, ctx: ctx, l2: l2, - emitter: emitter, attributes: nil, } } -func (eq *AttributesHandler) OnEvent(ev event.Event) { +func (eq *AttributesHandler) AttachEmitter(em event.Emitter) { + eq.emitter = em +} + +func (eq *AttributesHandler) OnEvent(ev event.Event) bool { // Events may be concurrent in the future. Prevent unsafe concurrent modifications to the attributes. eq.mu.Lock() defer eq.mu.Unlock() @@ -61,14 +65,43 @@ func (eq *AttributesHandler) OnEvent(ev event.Event) { eq.emitter.Emit(derive.ConfirmReceivedAttributesEvent{}) // to make sure we have a pre-state signal to process the attributes from eq.emitter.Emit(engine.PendingSafeRequestEvent{}) + case rollup.ResetEvent: + eq.sentAttributes = false + eq.attributes = nil + case rollup.EngineTemporaryErrorEvent: + eq.sentAttributes = false case engine.InvalidPayloadAttributesEvent: + if x.Attributes.DerivedFrom == (eth.L1BlockRef{}) { + return true // from sequencing + } + eq.sentAttributes = false // If the engine signals that attributes are invalid, // that should match our last applied attributes, which we should thus drop. eq.attributes = nil // Time to re-evaluate without attributes. // (the pending-safe state will then be forwarded to our source of attributes). eq.emitter.Emit(engine.PendingSafeRequestEvent{}) + case engine.PayloadSealExpiredErrorEvent: + if x.DerivedFrom == (eth.L1BlockRef{}) { + return true // from sequencing + } + eq.log.Warn("Block sealing job of derived attributes expired, job will be re-attempted.", + "build_id", x.Info.ID, "timestamp", x.Info.Timestamp, "err", x.Err) + // If the engine failed to seal temporarily, just allow to resubmit (triggered on next safe-head poke) + eq.sentAttributes = false + case engine.PayloadSealInvalidEvent: + if x.DerivedFrom == (eth.L1BlockRef{}) { + return true // from sequencing + } + eq.log.Warn("Cannot seal derived block attributes, input is invalid", + "build_id", x.Info.ID, "timestamp", x.Info.Timestamp, "err", x.Err) + eq.sentAttributes = false + eq.attributes = nil + eq.emitter.Emit(engine.PendingSafeRequestEvent{}) + default: + return false } + return true } // onPendingSafeUpdate applies the queued-up block attributes, if any, on top of the signaled pending state. @@ -82,6 +115,7 @@ func (eq *AttributesHandler) onPendingSafeUpdate(x engine.PendingSafeUpdateEvent } if eq.attributes == nil { + eq.sentAttributes = false // Request new attributes to be generated, only if we don't currently have attributes that have yet to be processed. // It is safe to request the pipeline, the attributes-handler is the only user of it, // and the pipeline will not generate another set of attributes until the last set is recognized. @@ -89,11 +123,19 @@ func (eq *AttributesHandler) onPendingSafeUpdate(x engine.PendingSafeUpdateEvent return } - // Drop attributes if they don't apply on top of the pending safe head + // Drop attributes if they don't apply on top of the pending safe head. + // This is expected after successful processing of these attributes. if eq.attributes.Parent.Number != x.PendingSafe.Number { - eq.log.Warn("dropping stale attributes", + eq.log.Debug("dropping stale attributes, requesting new ones", "pending", x.PendingSafe, "attributes_parent", eq.attributes.Parent) eq.attributes = nil + eq.sentAttributes = false + eq.emitter.Emit(derive.PipelineStepEvent{PendingSafe: x.PendingSafe}) + return + } + + if eq.sentAttributes { + eq.log.Warn("already sent the existing attributes") return } @@ -112,7 +154,8 @@ func (eq *AttributesHandler) onPendingSafeUpdate(x engine.PendingSafeUpdateEvent eq.consolidateNextSafeAttributes(eq.attributes, x.PendingSafe) } else { // append to tip otherwise - eq.emitter.Emit(engine.ProcessAttributesEvent{Attributes: eq.attributes}) + eq.sentAttributes = true + eq.emitter.Emit(engine.BuildStartEvent{Attributes: eq.attributes}) } } } @@ -138,8 +181,9 @@ func (eq *AttributesHandler) consolidateNextSafeAttributes(attributes *derive.At eq.log.Warn("L2 reorg: existing unsafe block does not match derived attributes from L1", "err", err, "unsafe", envelope.ExecutionPayload.ID(), "pending_safe", onto) + eq.sentAttributes = true // geth cannot wind back a chain without reorging to a new, previously non-canonical, block - eq.emitter.Emit(engine.ProcessAttributesEvent{Attributes: attributes}) + eq.emitter.Emit(engine.BuildStartEvent{Attributes: attributes}) return } else { ref, err := derive.PayloadToBlockRef(eq.cfg, envelope.ExecutionPayload) diff --git a/op-node/rollup/attributes/attributes_test.go b/op-node/rollup/attributes/attributes_test.go index 1833604ff3175..c3ed171ce92f2 100644 --- a/op-node/rollup/attributes/attributes_test.go +++ b/op-node/rollup/attributes/attributes_test.go @@ -31,6 +31,9 @@ func TestAttributesHandler(t *testing.T) { ParentHash: refA.Hash, Time: refA.Time + 12, } + // Copy with different hash, as alternative where the alt-L2 block may come from + refBAlt := refB + refBAlt.Hash = testutils.RandomHash(rng) aL1Info := &testutils.MockBlockInfo{ InfoParentHash: refA.ParentHash, @@ -116,6 +119,7 @@ func TestAttributesHandler(t *testing.T) { }, Parent: refA0, IsLastInSpan: true, + DerivedFrom: refB, } refA1, err := derive.PayloadToBlockRef(cfg, payloadA1.ExecutionPayload) require.NoError(t, err) @@ -152,6 +156,7 @@ func TestAttributesHandler(t *testing.T) { }, Parent: refA0, IsLastInSpan: true, + DerivedFrom: refBAlt, } refA1Alt, err := derive.PayloadToBlockRef(cfg, payloadA1Alt.ExecutionPayload) @@ -161,7 +166,8 @@ func TestAttributesHandler(t *testing.T) { logger := testlog.Logger(t, log.LevelInfo) l2 := &testutils.MockL2Client{} emitter := &testutils.MockEmitter{} - ah := NewAttributesHandler(logger, cfg, context.Background(), l2, emitter) + ah := NewAttributesHandler(logger, cfg, context.Background(), l2) + ah.AttachEmitter(emitter) emitter.ExpectOnce(derive.ConfirmReceivedAttributesEvent{}) emitter.ExpectOnce(engine.PendingSafeRequestEvent{}) @@ -182,7 +188,8 @@ func TestAttributesHandler(t *testing.T) { logger := testlog.Logger(t, log.LevelInfo) l2 := &testutils.MockL2Client{} emitter := &testutils.MockEmitter{} - ah := NewAttributesHandler(logger, cfg, context.Background(), l2, emitter) + ah := NewAttributesHandler(logger, cfg, context.Background(), l2) + ah.AttachEmitter(emitter) emitter.ExpectOnce(derive.ConfirmReceivedAttributesEvent{}) emitter.ExpectOnce(engine.PendingSafeRequestEvent{}) @@ -191,6 +198,8 @@ func TestAttributesHandler(t *testing.T) { }) emitter.AssertExpectations(t) require.NotNil(t, ah.attributes) + // New attributes will have to get generated after processing the last ones + emitter.ExpectOnce(derive.PipelineStepEvent{PendingSafe: refA1Alt}) ah.OnEvent(engine.PendingSafeUpdateEvent{ PendingSafe: refA1Alt, Unsafe: refA1Alt, @@ -204,7 +213,8 @@ func TestAttributesHandler(t *testing.T) { logger := testlog.Logger(t, log.LevelInfo) l2 := &testutils.MockL2Client{} emitter := &testutils.MockEmitter{} - ah := NewAttributesHandler(logger, cfg, context.Background(), l2, emitter) + ah := NewAttributesHandler(logger, cfg, context.Background(), l2) + ah.AttachEmitter(emitter) emitter.ExpectOnce(derive.ConfirmReceivedAttributesEvent{}) emitter.ExpectOnce(engine.PendingSafeRequestEvent{}) @@ -229,7 +239,8 @@ func TestAttributesHandler(t *testing.T) { logger := testlog.Logger(t, log.LevelInfo) l2 := &testutils.MockL2Client{} emitter := &testutils.MockEmitter{} - ah := NewAttributesHandler(logger, cfg, context.Background(), l2, emitter) + ah := NewAttributesHandler(logger, cfg, context.Background(), l2) + ah.AttachEmitter(emitter) // attrA1Alt does not match block A1, so will cause force-reorg. emitter.ExpectOnce(derive.ConfirmReceivedAttributesEvent{}) @@ -242,7 +253,7 @@ func TestAttributesHandler(t *testing.T) { // The payloadA1 is going to get reorged out in favor of attrA1Alt (turns into payloadA1Alt) l2.ExpectPayloadByNumber(refA1.Number, payloadA1, nil) // fail consolidation, perform force reorg - emitter.ExpectOnce(engine.ProcessAttributesEvent{Attributes: attrA1Alt}) + emitter.ExpectOnce(engine.BuildStartEvent{Attributes: attrA1Alt}) ah.OnEvent(engine.PendingSafeUpdateEvent{ PendingSafe: refA0, Unsafe: refA1, @@ -251,6 +262,7 @@ func TestAttributesHandler(t *testing.T) { emitter.AssertExpectations(t) require.NotNil(t, ah.attributes, "still have attributes, processing still unconfirmed") + emitter.ExpectOnce(derive.PipelineStepEvent{PendingSafe: refA1Alt}) // recognize reorg as complete ah.OnEvent(engine.PendingSafeUpdateEvent{ PendingSafe: refA1Alt, @@ -264,7 +276,8 @@ func TestAttributesHandler(t *testing.T) { logger := testlog.Logger(t, log.LevelInfo) l2 := &testutils.MockL2Client{} emitter := &testutils.MockEmitter{} - ah := NewAttributesHandler(logger, cfg, context.Background(), l2, emitter) + ah := NewAttributesHandler(logger, cfg, context.Background(), l2) + ah.AttachEmitter(emitter) attr := &derive.AttributesWithParent{ Attributes: attrA1.Attributes, // attributes will match, passing consolidation @@ -294,6 +307,7 @@ func TestAttributesHandler(t *testing.T) { emitter.AssertExpectations(t) require.NotNil(t, ah.attributes, "still have attributes, processing still unconfirmed") + emitter.ExpectOnce(derive.PipelineStepEvent{PendingSafe: refA1}) ah.OnEvent(engine.PendingSafeUpdateEvent{ PendingSafe: refA1, Unsafe: refA1, @@ -316,7 +330,8 @@ func TestAttributesHandler(t *testing.T) { logger := testlog.Logger(t, log.LevelInfo) l2 := &testutils.MockL2Client{} emitter := &testutils.MockEmitter{} - ah := NewAttributesHandler(logger, cfg, context.Background(), l2, emitter) + ah := NewAttributesHandler(logger, cfg, context.Background(), l2) + ah.AttachEmitter(emitter) emitter.ExpectOnce(derive.ConfirmReceivedAttributesEvent{}) emitter.ExpectOnce(engine.PendingSafeRequestEvent{}) @@ -328,7 +343,7 @@ func TestAttributesHandler(t *testing.T) { require.True(t, attrA1Alt.IsLastInSpan, "must be last in span for attributes to become safe") // attrA1Alt will fit right on top of A0 - emitter.ExpectOnce(engine.ProcessAttributesEvent{Attributes: attrA1Alt}) + emitter.ExpectOnce(engine.BuildStartEvent{Attributes: attrA1Alt}) ah.OnEvent(engine.PendingSafeUpdateEvent{ PendingSafe: refA0, Unsafe: refA0, @@ -337,6 +352,7 @@ func TestAttributesHandler(t *testing.T) { emitter.AssertExpectations(t) require.NotNil(t, ah.attributes) + emitter.ExpectOnce(derive.PipelineStepEvent{PendingSafe: refA1Alt}) ah.OnEvent(engine.PendingSafeUpdateEvent{ PendingSafe: refA1Alt, Unsafe: refA1Alt, @@ -351,7 +367,8 @@ func TestAttributesHandler(t *testing.T) { logger := testlog.Logger(t, log.LevelInfo) l2 := &testutils.MockL2Client{} emitter := &testutils.MockEmitter{} - ah := NewAttributesHandler(logger, cfg, context.Background(), l2, emitter) + ah := NewAttributesHandler(logger, cfg, context.Background(), l2) + ah.AttachEmitter(emitter) emitter.ExpectOnceType("ResetEvent") ah.OnEvent(engine.PendingSafeUpdateEvent{ @@ -366,7 +383,8 @@ func TestAttributesHandler(t *testing.T) { logger := testlog.Logger(t, log.LevelInfo) l2 := &testutils.MockL2Client{} emitter := &testutils.MockEmitter{} - ah := NewAttributesHandler(logger, cfg, context.Background(), l2, emitter) + ah := NewAttributesHandler(logger, cfg, context.Background(), l2) + ah.AttachEmitter(emitter) // If there are no attributes, we expect the pipeline to be requested to generate attributes. emitter.ExpectOnce(derive.PipelineStepEvent{PendingSafe: refA1}) diff --git a/op-node/rollup/clsync/clsync.go b/op-node/rollup/clsync/clsync.go index 214ab9e9d3c83..64193b21b110d 100644 --- a/op-node/rollup/clsync/clsync.go +++ b/op-node/rollup/clsync/clsync.go @@ -33,16 +33,19 @@ type CLSync struct { unsafePayloads *PayloadsQueue // queue of unsafe payloads, ordered by ascending block number, may have gaps and duplicates } -func NewCLSync(log log.Logger, cfg *rollup.Config, metrics Metrics, emitter event.Emitter) *CLSync { +func NewCLSync(log log.Logger, cfg *rollup.Config, metrics Metrics) *CLSync { return &CLSync{ log: log, cfg: cfg, metrics: metrics, - emitter: emitter, unsafePayloads: NewPayloadsQueue(log, maxUnsafePayloadsMemory, payloadMemSize), } } +func (eq *CLSync) AttachEmitter(em event.Emitter) { + eq.emitter = em +} + // LowestQueuedUnsafeBlock retrieves the first queued-up L2 unsafe payload, or a zeroed reference if there is none. func (eq *CLSync) LowestQueuedUnsafeBlock() eth.L2BlockRef { payload := eq.unsafePayloads.Peek() @@ -64,24 +67,27 @@ func (ev ReceivedUnsafePayloadEvent) String() string { return "received-unsafe-payload" } -func (eq *CLSync) OnEvent(ev event.Event) { +func (eq *CLSync) OnEvent(ev event.Event) bool { // Events may be concurrent in the future. Prevent unsafe concurrent modifications to the payloads queue. eq.mu.Lock() defer eq.mu.Unlock() switch x := ev.(type) { - case engine.InvalidPayloadEvent: + case engine.PayloadInvalidEvent: eq.onInvalidPayload(x) case engine.ForkchoiceUpdateEvent: eq.onForkchoiceUpdate(x) case ReceivedUnsafePayloadEvent: eq.onUnsafePayload(x) + default: + return false } + return true } // onInvalidPayload checks if the first next-up payload matches the invalid payload. // If so, the payload is dropped, to give the next payloads a try. -func (eq *CLSync) onInvalidPayload(x engine.InvalidPayloadEvent) { +func (eq *CLSync) onInvalidPayload(x engine.PayloadInvalidEvent) { eq.log.Debug("CL sync received invalid-payload report", x.Envelope.ExecutionPayload.ID()) block := x.Envelope.ExecutionPayload diff --git a/op-node/rollup/clsync/clsync_test.go b/op-node/rollup/clsync/clsync_test.go index f42c67f9220e5..944d2027caff7 100644 --- a/op-node/rollup/clsync/clsync_test.go +++ b/op-node/rollup/clsync/clsync_test.go @@ -1,6 +1,7 @@ package clsync import ( + "errors" "math/big" "math/rand" // nosemgrep "testing" @@ -127,7 +128,8 @@ func TestCLSync(t *testing.T) { logger := testlog.Logger(t, log.LevelError) emitter := &testutils.MockEmitter{} - cl := NewCLSync(logger, cfg, metrics, emitter) + cl := NewCLSync(logger, cfg, metrics) + cl.AttachEmitter(emitter) emitter.ExpectOnce(engine.ForkchoiceRequestEvent{}) cl.OnEvent(ReceivedUnsafePayloadEvent{Envelope: payloadA1}) @@ -148,7 +150,8 @@ func TestCLSync(t *testing.T) { logger := testlog.Logger(t, log.LevelError) emitter := &testutils.MockEmitter{} - cl := NewCLSync(logger, cfg, metrics, emitter) + cl := NewCLSync(logger, cfg, metrics) + cl.AttachEmitter(emitter) emitter.ExpectOnce(engine.ForkchoiceRequestEvent{}) cl.OnEvent(ReceivedUnsafePayloadEvent{Envelope: payloadA1}) @@ -170,7 +173,8 @@ func TestCLSync(t *testing.T) { logger := testlog.Logger(t, log.LevelError) emitter := &testutils.MockEmitter{} - cl := NewCLSync(logger, cfg, metrics, emitter) + cl := NewCLSync(logger, cfg, metrics) + cl.AttachEmitter(emitter) emitter.ExpectOnce(engine.ForkchoiceRequestEvent{}) cl.OnEvent(ReceivedUnsafePayloadEvent{Envelope: payloadA1}) @@ -190,7 +194,8 @@ func TestCLSync(t *testing.T) { logger := testlog.Logger(t, log.LevelError) emitter := &testutils.MockEmitter{} - cl := NewCLSync(logger, cfg, metrics, emitter) + cl := NewCLSync(logger, cfg, metrics) + cl.AttachEmitter(emitter) emitter.ExpectOnce(engine.ForkchoiceRequestEvent{}) cl.OnEvent(ReceivedUnsafePayloadEvent{Envelope: payloadA2}) @@ -210,7 +215,8 @@ func TestCLSync(t *testing.T) { logger := testlog.Logger(t, log.LevelError) emitter := &testutils.MockEmitter{} - cl := NewCLSync(logger, cfg, metrics, emitter) + cl := NewCLSync(logger, cfg, metrics) + cl.AttachEmitter(emitter) emitter.AssertExpectations(t) // nothing to process yet require.Nil(t, cl.unsafePayloads.Peek(), "no payloads yet") @@ -268,7 +274,8 @@ func TestCLSync(t *testing.T) { logger := testlog.Logger(t, log.LevelError) emitter := &testutils.MockEmitter{} - cl := NewCLSync(logger, cfg, metrics, emitter) + cl := NewCLSync(logger, cfg, metrics) + cl.AttachEmitter(emitter) emitter.ExpectOnce(engine.ForkchoiceRequestEvent{}) cl.OnEvent(ReceivedUnsafePayloadEvent{Envelope: payloadA1}) @@ -312,7 +319,8 @@ func TestCLSync(t *testing.T) { logger := testlog.Logger(t, log.LevelError) emitter := &testutils.MockEmitter{} - cl := NewCLSync(logger, cfg, metrics, emitter) + cl := NewCLSync(logger, cfg, metrics) + cl.AttachEmitter(emitter) emitter.ExpectOnce(engine.ForkchoiceRequestEvent{}) cl.OnEvent(ReceivedUnsafePayloadEvent{Envelope: payloadA1}) @@ -352,7 +360,8 @@ func TestCLSync(t *testing.T) { t.Run("invalid payload error", func(t *testing.T) { logger := testlog.Logger(t, log.LevelError) emitter := &testutils.MockEmitter{} - cl := NewCLSync(logger, cfg, metrics, emitter) + cl := NewCLSync(logger, cfg, metrics) + cl.AttachEmitter(emitter) // CLSync gets payload and requests engine state, to later determine if payload should be forwarded emitter.ExpectOnce(engine.ForkchoiceRequestEvent{}) @@ -369,7 +378,7 @@ func TestCLSync(t *testing.T) { emitter.AssertExpectations(t) // Pretend the payload is bad. It should not be retried after this. - cl.OnEvent(engine.InvalidPayloadEvent{Envelope: payloadA1}) + cl.OnEvent(engine.PayloadInvalidEvent{Envelope: payloadA1, Err: errors.New("test err")}) emitter.AssertExpectations(t) require.Nil(t, cl.unsafePayloads.Peek(), "pop because invalid") }) diff --git a/op-node/rollup/driver/conf_depth.go b/op-node/rollup/confdepth/conf_depth.go similarity index 98% rename from op-node/rollup/driver/conf_depth.go rename to op-node/rollup/confdepth/conf_depth.go index 194692bf39dbd..4c3cd2f8b942b 100644 --- a/op-node/rollup/driver/conf_depth.go +++ b/op-node/rollup/confdepth/conf_depth.go @@ -1,4 +1,4 @@ -package driver +package confdepth import ( "context" diff --git a/op-node/rollup/driver/conf_depth_test.go b/op-node/rollup/confdepth/conf_depth_test.go similarity index 99% rename from op-node/rollup/driver/conf_depth_test.go rename to op-node/rollup/confdepth/conf_depth_test.go index 1155cdd52f901..536075b209a88 100644 --- a/op-node/rollup/driver/conf_depth_test.go +++ b/op-node/rollup/confdepth/conf_depth_test.go @@ -1,4 +1,4 @@ -package driver +package confdepth import ( "context" diff --git a/op-node/rollup/derive/deriver.go b/op-node/rollup/derive/deriver.go index c286a7dd75883..760891648524c 100644 --- a/op-node/rollup/derive/deriver.go +++ b/op-node/rollup/derive/deriver.go @@ -73,15 +73,18 @@ type PipelineDeriver struct { needAttributesConfirmation bool } -func NewPipelineDeriver(ctx context.Context, pipeline *DerivationPipeline, emitter event.Emitter) *PipelineDeriver { +func NewPipelineDeriver(ctx context.Context, pipeline *DerivationPipeline) *PipelineDeriver { return &PipelineDeriver{ pipeline: pipeline, ctx: ctx, - emitter: emitter, } } -func (d *PipelineDeriver) OnEvent(ev event.Event) { +func (d *PipelineDeriver) AttachEmitter(em event.Emitter) { + d.emitter = em +} + +func (d *PipelineDeriver) OnEvent(ev event.Event) bool { switch x := ev.(type) { case rollup.ResetEvent: d.pipeline.Reset() @@ -89,7 +92,7 @@ func (d *PipelineDeriver) OnEvent(ev event.Event) { // Don't generate attributes if there are already attributes in-flight if d.needAttributesConfirmation { d.pipeline.log.Debug("Previously sent attributes are unconfirmed to be received") - return + return true } d.pipeline.log.Trace("Derivation pipeline step", "onto_origin", d.pipeline.Origin()) preOrigin := d.pipeline.Origin() @@ -128,5 +131,8 @@ func (d *PipelineDeriver) OnEvent(ev event.Event) { d.pipeline.ConfirmEngineReset() case ConfirmReceivedAttributesEvent: d.needAttributesConfirmation = false + default: + return false } + return true } diff --git a/op-node/rollup/driver/driver.go b/op-node/rollup/driver/driver.go index 75531c42dfcd7..f1fc878c314b8 100644 --- a/op-node/rollup/driver/driver.go +++ b/op-node/rollup/driver/driver.go @@ -2,9 +2,6 @@ package driver import ( "context" - "time" - - "golang.org/x/time/rate" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" @@ -14,16 +11,24 @@ import ( "github.com/ethereum-optimism/optimism/op-node/rollup/attributes" "github.com/ethereum-optimism/optimism/op-node/rollup/clsync" "github.com/ethereum-optimism/optimism/op-node/rollup/conductor" + "github.com/ethereum-optimism/optimism/op-node/rollup/confdepth" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-node/rollup/engine" "github.com/ethereum-optimism/optimism/op-node/rollup/event" "github.com/ethereum-optimism/optimism/op-node/rollup/finality" + "github.com/ethereum-optimism/optimism/op-node/rollup/sequencing" "github.com/ethereum-optimism/optimism/op-node/rollup/status" "github.com/ethereum-optimism/optimism/op-node/rollup/sync" plasma "github.com/ethereum-optimism/optimism/op-plasma" "github.com/ethereum-optimism/optimism/op-service/eth" ) +// aliases to not disrupt op-conductor code +var ( + ErrSequencerAlreadyStarted = sequencing.ErrSequencerAlreadyStarted + ErrSequencerAlreadyStopped = sequencing.ErrSequencerAlreadyStopped +) + type Metrics interface { RecordPipelineReset() RecordPublishingError() @@ -46,11 +51,10 @@ type Metrics interface { RecordL1ReorgDepth(d uint64) - EngineMetrics + engine.Metrics L1FetcherMetrics - SequencerMetrics event.Metrics - RecordEventsRateLimited() + sequencing.Metrics } type L1Chain interface { @@ -116,15 +120,6 @@ type SyncStatusTracker interface { L1Head() eth.L1BlockRef } -type SequencerIface interface { - StartBuildingBlock(ctx context.Context) error - CompleteBuildingBlock(ctx context.Context, agossip async.AsyncGossiper, sequencerConductor conductor.SequencerConductor) (*eth.ExecutionPayloadEnvelope, error) - PlanNextSequencerAction() time.Duration - RunNextSequencerAction(ctx context.Context, agossip async.AsyncGossiper, sequencerConductor conductor.SequencerConductor) (*eth.ExecutionPayloadEnvelope, error) - BuildingOnto() eth.L2BlockRef - CancelBuildingBlock(ctx context.Context) -} - type Network interface { // PublishL2Payload is called by the driver whenever there is a new payload to publish, synchronously with the driver main loop. PublishL2Payload(ctx context.Context, payload *eth.ExecutionPayloadEnvelope) error @@ -154,14 +149,6 @@ type SequencerStateListener interface { SequencerStopped() error } -// 10,000 events per second is plenty. -// If we are going through more events, the driver needs to breathe, and warn the user of a potential issue. -const eventsLimit = rate.Limit(10_000) - -// 500 events of burst: the maximum amount of events to eat up -// past the rate limit before the rate limit becomes applicable. -const eventsBurst = 500 - // NewDriver composes an events handler that tracks L1 state, triggers L2 Derivation, and optionally sequences new L2 blocks. func NewDriver( driverCfg *Config, @@ -173,49 +160,60 @@ func NewDriver( network Network, log log.Logger, metrics Metrics, - sequencerStateListener SequencerStateListener, + sequencerStateListener sequencing.SequencerStateListener, safeHeadListener rollup.SafeHeadListener, syncCfg *sync.Config, sequencerConductor conductor.SequencerConductor, plasma PlasmaIface, ) *Driver { driverCtx, driverCancel := context.WithCancel(context.Background()) - rootDeriver := &event.DeriverMux{} - var synchronousEvents event.EmitterDrainer - synchronousEvents = event.NewQueue(log, driverCtx, rootDeriver, metrics) - synchronousEvents = event.NewLimiterDrainer(context.Background(), synchronousEvents, eventsLimit, eventsBurst, func() { - metrics.RecordEventsRateLimited() - log.Warn("Driver is hitting events rate limit.") - }) + + var executor event.Executor + var drain func() error + // This instantiation will be one of more options: soon there will be a parallel events executor + { + s := event.NewGlobalSynchronous(driverCtx) + executor = s + drain = s.Drain + } + sys := event.NewSystem(log, executor) + sys.AddTracer(event.NewMetricsTracer(metrics)) + + opts := event.DefaultRegisterOpts() statusTracker := status.NewStatusTracker(log, metrics) + sys.Register("status", statusTracker, opts) l1 = NewMeteredL1Fetcher(l1, metrics) - sequencerConfDepth := NewConfDepth(driverCfg.SequencerConfDepth, statusTracker.L1Head, l1) - findL1Origin := NewL1OriginSelector(log, cfg, sequencerConfDepth) - verifConfDepth := NewConfDepth(driverCfg.VerifierConfDepth, statusTracker.L1Head, l1) - ec := engine.NewEngineController(l2, log, metrics, cfg, syncCfg, synchronousEvents) - engineResetDeriver := engine.NewEngineResetDeriver(driverCtx, log, cfg, l1, l2, syncCfg, synchronousEvents) - clSync := clsync.NewCLSync(log, cfg, metrics, synchronousEvents) + verifConfDepth := confdepth.NewConfDepth(driverCfg.VerifierConfDepth, statusTracker.L1Head, l1) + + ec := engine.NewEngineController(l2, log, metrics, cfg, syncCfg, + sys.Register("engine-controller", nil, opts)) + + sys.Register("engine-reset", + engine.NewEngineResetDeriver(driverCtx, log, cfg, l1, l2, syncCfg), opts) + + clSync := clsync.NewCLSync(log, cfg, metrics) // alt-sync still uses cl-sync state to determine what to sync to + sys.Register("cl-sync", clSync, opts) var finalizer Finalizer if cfg.PlasmaEnabled() { - finalizer = finality.NewPlasmaFinalizer(driverCtx, log, cfg, l1, synchronousEvents, plasma) + finalizer = finality.NewPlasmaFinalizer(driverCtx, log, cfg, l1, plasma) } else { - finalizer = finality.NewFinalizer(driverCtx, log, cfg, l1, synchronousEvents) + finalizer = finality.NewFinalizer(driverCtx, log, cfg, l1) } + sys.Register("finalizer", finalizer, opts) + + sys.Register("attributes-handler", + attributes.NewAttributesHandler(log, cfg, driverCtx, l2), opts) - attributesHandler := attributes.NewAttributesHandler(log, cfg, driverCtx, l2, synchronousEvents) derivationPipeline := derive.NewDerivationPipeline(log, cfg, verifConfDepth, l1Blobs, plasma, l2, metrics) - pipelineDeriver := derive.NewPipelineDeriver(driverCtx, derivationPipeline, synchronousEvents) - attrBuilder := derive.NewFetchingAttributesBuilder(cfg, l1, l2) - meteredEngine := NewMeteredEngine(cfg, ec, metrics, log) // Only use the metered engine in the sequencer b/c it records sequencing metrics. - sequencer := NewSequencer(log, cfg, meteredEngine, attrBuilder, findL1Origin, metrics) - asyncGossiper := async.NewAsyncGossiper(driverCtx, network, log, metrics) + + sys.Register("pipeline", + derive.NewPipelineDeriver(driverCtx, derivationPipeline), opts) syncDeriver := &SyncDeriver{ Derivation: derivationPipeline, - Finalizer: finalizer, SafeHeadNotifs: safeHeadListener, CLSync: clSync, Engine: ec, @@ -223,52 +221,52 @@ func NewDriver( Config: cfg, L1: l1, L2: l2, - Emitter: synchronousEvents, Log: log, Ctx: driverCtx, - Drain: synchronousEvents.Drain, + Drain: drain, } - engDeriv := engine.NewEngDeriver(log, driverCtx, cfg, ec, synchronousEvents) - schedDeriv := NewStepSchedulingDeriver(log, synchronousEvents) - - driver := &Driver{ - statusTracker: statusTracker, - SyncDeriver: syncDeriver, - sched: schedDeriv, - synchronousEvents: synchronousEvents, - stateReq: make(chan chan struct{}), - forceReset: make(chan chan struct{}, 10), - startSequencer: make(chan hashAndErrorChannel, 10), - stopSequencer: make(chan chan hashAndError, 10), - sequencerActive: make(chan chan bool, 10), - sequencerNotifs: sequencerStateListener, - driverConfig: driverCfg, - driverCtx: driverCtx, - driverCancel: driverCancel, - log: log, - sequencer: sequencer, - network: network, - metrics: metrics, - l1HeadSig: make(chan eth.L1BlockRef, 10), - l1SafeSig: make(chan eth.L1BlockRef, 10), - l1FinalizedSig: make(chan eth.L1BlockRef, 10), - unsafeL2Payloads: make(chan *eth.ExecutionPayloadEnvelope, 10), - altSync: altSync, - asyncGossiper: asyncGossiper, - sequencerConductor: sequencerConductor, + sys.Register("sync", syncDeriver, opts) + + sys.Register("engine", engine.NewEngDeriver(log, driverCtx, cfg, metrics, ec), opts) + + schedDeriv := NewStepSchedulingDeriver(log) + sys.Register("step-scheduler", schedDeriv, opts) + + var sequencer sequencing.SequencerIface + if driverCfg.SequencerEnabled { + asyncGossiper := async.NewAsyncGossiper(driverCtx, network, log, metrics) + attrBuilder := derive.NewFetchingAttributesBuilder(cfg, l1, l2) + sequencerConfDepth := confdepth.NewConfDepth(driverCfg.SequencerConfDepth, statusTracker.L1Head, l1) + findL1Origin := sequencing.NewL1OriginSelector(log, cfg, sequencerConfDepth) + sequencer = sequencing.NewSequencer(driverCtx, log, cfg, attrBuilder, findL1Origin, + sequencerStateListener, sequencerConductor, asyncGossiper, metrics) + sys.Register("sequencer", sequencer, opts) + } else { + sequencer = sequencing.DisabledSequencer{} } - *rootDeriver = []event.Deriver{ - syncDeriver, - engineResetDeriver, - engDeriv, - schedDeriv, - driver, - clSync, - pipelineDeriver, - attributesHandler, - finalizer, - statusTracker, + driverEmitter := sys.Register("driver", nil, opts) + driver := &Driver{ + eventSys: sys, + statusTracker: statusTracker, + SyncDeriver: syncDeriver, + sched: schedDeriv, + emitter: driverEmitter, + drain: drain, + stateReq: make(chan chan struct{}), + forceReset: make(chan chan struct{}, 10), + driverConfig: driverCfg, + driverCtx: driverCtx, + driverCancel: driverCancel, + log: log, + sequencer: sequencer, + network: network, + metrics: metrics, + l1HeadSig: make(chan eth.L1BlockRef, 10), + l1SafeSig: make(chan eth.L1BlockRef, 10), + l1FinalizedSig: make(chan eth.L1BlockRef, 10), + unsafeL2Payloads: make(chan *eth.ExecutionPayloadEnvelope, 10), + altSync: altSync, } return driver diff --git a/op-node/rollup/driver/metered_engine.go b/op-node/rollup/driver/metered_engine.go deleted file mode 100644 index 41f207a50962c..0000000000000 --- a/op-node/rollup/driver/metered_engine.go +++ /dev/null @@ -1,97 +0,0 @@ -package driver - -import ( - "context" - "time" - - "github.com/ethereum/go-ethereum/log" - - "github.com/ethereum-optimism/optimism/op-node/rollup" - "github.com/ethereum-optimism/optimism/op-node/rollup/async" - "github.com/ethereum-optimism/optimism/op-node/rollup/conductor" - "github.com/ethereum-optimism/optimism/op-node/rollup/derive" - "github.com/ethereum-optimism/optimism/op-node/rollup/engine" - "github.com/ethereum-optimism/optimism/op-service/eth" -) - -type EngineMetrics interface { - RecordSequencingError() - CountSequencedTxs(count int) - - RecordSequencerBuildingDiffTime(duration time.Duration) - RecordSequencerSealingTime(duration time.Duration) -} - -// MeteredEngine wraps an EngineControl and adds metrics such as block building time diff and sealing time -type MeteredEngine struct { - inner engine.EngineControl - - cfg *rollup.Config - metrics EngineMetrics - log log.Logger - - buildingStartTime time.Time -} - -func NewMeteredEngine(cfg *rollup.Config, inner engine.EngineControl, metrics EngineMetrics, log log.Logger) *MeteredEngine { - return &MeteredEngine{ - inner: inner, - cfg: cfg, - metrics: metrics, - log: log, - } -} - -func (m *MeteredEngine) Finalized() eth.L2BlockRef { - return m.inner.Finalized() -} - -func (m *MeteredEngine) UnsafeL2Head() eth.L2BlockRef { - return m.inner.UnsafeL2Head() -} - -func (m *MeteredEngine) SafeL2Head() eth.L2BlockRef { - return m.inner.SafeL2Head() -} - -func (m *MeteredEngine) StartPayload(ctx context.Context, parent eth.L2BlockRef, attrs *derive.AttributesWithParent, updateSafe bool) (errType engine.BlockInsertionErrType, err error) { - m.buildingStartTime = time.Now() - errType, err = m.inner.StartPayload(ctx, parent, attrs, updateSafe) - if err != nil { - m.metrics.RecordSequencingError() - } - return errType, err -} - -func (m *MeteredEngine) ConfirmPayload(ctx context.Context, agossip async.AsyncGossiper, sequencerConductor conductor.SequencerConductor) (out *eth.ExecutionPayloadEnvelope, errTyp engine.BlockInsertionErrType, err error) { - sealingStart := time.Now() - // Actually execute the block and add it to the head of the chain. - payload, errType, err := m.inner.ConfirmPayload(ctx, agossip, sequencerConductor) - if err != nil { - m.metrics.RecordSequencingError() - return payload, errType, err - } - now := time.Now() - sealTime := now.Sub(sealingStart) - buildTime := now.Sub(m.buildingStartTime) - m.metrics.RecordSequencerSealingTime(sealTime) - m.metrics.RecordSequencerBuildingDiffTime(buildTime - time.Duration(m.cfg.BlockTime)*time.Second) - - txnCount := len(payload.ExecutionPayload.Transactions) - m.metrics.CountSequencedTxs(txnCount) - - ref := m.inner.UnsafeL2Head() - - m.log.Debug("Processed new L2 block", "l2_unsafe", ref, "l1_origin", ref.L1Origin, - "txs", txnCount, "time", ref.Time, "seal_time", sealTime, "build_time", buildTime) - - return payload, errType, err -} - -func (m *MeteredEngine) CancelPayload(ctx context.Context, force bool) error { - return m.inner.CancelPayload(ctx, force) -} - -func (m *MeteredEngine) BuildingPayload() (onto eth.L2BlockRef, id eth.PayloadID, safe bool) { - return m.inner.BuildingPayload() -} diff --git a/op-node/rollup/driver/sequencer.go b/op-node/rollup/driver/sequencer.go deleted file mode 100644 index c40d76f089220..0000000000000 --- a/op-node/rollup/driver/sequencer.go +++ /dev/null @@ -1,274 +0,0 @@ -package driver - -import ( - "context" - "errors" - "fmt" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/log" - - "github.com/ethereum-optimism/optimism/op-node/rollup" - "github.com/ethereum-optimism/optimism/op-node/rollup/async" - "github.com/ethereum-optimism/optimism/op-node/rollup/conductor" - "github.com/ethereum-optimism/optimism/op-node/rollup/derive" - "github.com/ethereum-optimism/optimism/op-node/rollup/engine" - "github.com/ethereum-optimism/optimism/op-service/eth" -) - -type Downloader interface { - InfoByHash(ctx context.Context, hash common.Hash) (eth.BlockInfo, error) - FetchReceipts(ctx context.Context, blockHash common.Hash) (eth.BlockInfo, types.Receipts, error) -} - -type L1OriginSelectorIface interface { - FindL1Origin(ctx context.Context, l2Head eth.L2BlockRef) (eth.L1BlockRef, error) -} - -type SequencerMetrics interface { - RecordSequencerInconsistentL1Origin(from eth.BlockID, to eth.BlockID) - RecordSequencerReset() -} - -// Sequencer implements the sequencing interface of the driver: it starts and completes block building jobs. -type Sequencer struct { - log log.Logger - rollupCfg *rollup.Config - spec *rollup.ChainSpec - - engine engine.EngineControl - - attrBuilder derive.AttributesBuilder - l1OriginSelector L1OriginSelectorIface - - metrics SequencerMetrics - - // timeNow enables sequencer testing to mock the time - timeNow func() time.Time - - nextAction time.Time -} - -func NewSequencer(log log.Logger, rollupCfg *rollup.Config, engine engine.EngineControl, attributesBuilder derive.AttributesBuilder, l1OriginSelector L1OriginSelectorIface, metrics SequencerMetrics) *Sequencer { - return &Sequencer{ - log: log, - rollupCfg: rollupCfg, - spec: rollup.NewChainSpec(rollupCfg), - engine: engine, - timeNow: time.Now, - attrBuilder: attributesBuilder, - l1OriginSelector: l1OriginSelector, - metrics: metrics, - } -} - -// StartBuildingBlock initiates a block building job on top of the given L2 head, safe and finalized blocks, and using the provided l1Origin. -func (d *Sequencer) StartBuildingBlock(ctx context.Context) error { - l2Head := d.engine.UnsafeL2Head() - - // Figure out which L1 origin block we're going to be building on top of. - l1Origin, err := d.l1OriginSelector.FindL1Origin(ctx, l2Head) - if err != nil { - d.log.Error("Error finding next L1 Origin", "err", err) - return err - } - - if !(l2Head.L1Origin.Hash == l1Origin.ParentHash || l2Head.L1Origin.Hash == l1Origin.Hash) { - d.metrics.RecordSequencerInconsistentL1Origin(l2Head.L1Origin, l1Origin.ID()) - return derive.NewResetError(fmt.Errorf("cannot build new L2 block with L1 origin %s (parent L1 %s) on current L2 head %s with L1 origin %s", l1Origin, l1Origin.ParentHash, l2Head, l2Head.L1Origin)) - } - - d.log.Info("creating new block", "parent", l2Head, "l1Origin", l1Origin) - - fetchCtx, cancel := context.WithTimeout(ctx, time.Second*20) - defer cancel() - - attrs, err := d.attrBuilder.PreparePayloadAttributes(fetchCtx, l2Head, l1Origin.ID()) - if err != nil { - return err - } - - // If our next L2 block timestamp is beyond the Sequencer drift threshold, then we must produce - // empty blocks (other than the L1 info deposit and any user deposits). We handle this by - // setting NoTxPool to true, which will cause the Sequencer to not include any transactions - // from the transaction pool. - attrs.NoTxPool = uint64(attrs.Timestamp) > l1Origin.Time+d.spec.MaxSequencerDrift(l1Origin.Time) - - // For the Ecotone activation block we shouldn't include any sequencer transactions. - if d.rollupCfg.IsEcotoneActivationBlock(uint64(attrs.Timestamp)) { - attrs.NoTxPool = true - d.log.Info("Sequencing Ecotone upgrade block") - } - - // For the Fjord activation block we shouldn't include any sequencer transactions. - if d.rollupCfg.IsFjordActivationBlock(uint64(attrs.Timestamp)) { - attrs.NoTxPool = true - d.log.Info("Sequencing Fjord upgrade block") - } - - d.log.Debug("prepared attributes for new block", - "num", l2Head.Number+1, "time", uint64(attrs.Timestamp), - "origin", l1Origin, "origin_time", l1Origin.Time, "noTxPool", attrs.NoTxPool) - - // Start a payload building process. - withParent := &derive.AttributesWithParent{Attributes: attrs, Parent: l2Head, IsLastInSpan: false} - errTyp, err := d.engine.StartPayload(ctx, l2Head, withParent, false) - if err != nil { - return fmt.Errorf("failed to start building on top of L2 chain %s, error (%d): %w", l2Head, errTyp, err) - } - return nil -} - -// CompleteBuildingBlock takes the current block that is being built, and asks the engine to complete the building, seal the block, and persist it as canonical. -// Warning: the safe and finalized L2 blocks as viewed during the initiation of the block building are reused for completion of the block building. -// The Execution engine should not change the safe and finalized blocks between start and completion of block building. -func (d *Sequencer) CompleteBuildingBlock(ctx context.Context, agossip async.AsyncGossiper, sequencerConductor conductor.SequencerConductor) (*eth.ExecutionPayloadEnvelope, error) { - envelope, errTyp, err := d.engine.ConfirmPayload(ctx, agossip, sequencerConductor) - if err != nil { - return nil, fmt.Errorf("failed to complete building block: error (%d): %w", errTyp, err) - } - return envelope, nil -} - -// CancelBuildingBlock cancels the current open block building job. -// This sequencer only maintains one block building job at a time. -func (d *Sequencer) CancelBuildingBlock(ctx context.Context) { - // force-cancel, we can always continue block building, and any error is logged by the engine state - _ = d.engine.CancelPayload(ctx, true) -} - -// PlanNextSequencerAction returns a desired delay till the RunNextSequencerAction call. -func (d *Sequencer) PlanNextSequencerAction() time.Duration { - buildingOnto, buildingID, safe := d.engine.BuildingPayload() - // If the engine is busy building safe blocks (and thus changing the head that we would sync on top of), - // then give it time to sync up. - if safe { - d.log.Warn("delaying sequencing to not interrupt safe-head changes", "onto", buildingOnto, "onto_time", buildingOnto.Time) - // approximates the worst-case time it takes to build a block, to reattempt sequencing after. - return time.Second * time.Duration(d.rollupCfg.BlockTime) - } - - head := d.engine.UnsafeL2Head() - now := d.timeNow() - - // We may have to wait till the next sequencing action, e.g. upon an error. - // If the head changed we need to respond and will not delay the sequencing. - if delay := d.nextAction.Sub(now); delay > 0 && buildingOnto.Hash == head.Hash { - return delay - } - - blockTime := time.Duration(d.rollupCfg.BlockTime) * time.Second - payloadTime := time.Unix(int64(head.Time+d.rollupCfg.BlockTime), 0) - remainingTime := payloadTime.Sub(now) - - // If we started building a block already, and if that work is still consistent, - // then we would like to finish it by sealing the block. - if buildingID != (eth.PayloadID{}) && buildingOnto.Hash == head.Hash { - // if we started building already, then we will schedule the sealing. - if remainingTime < sealingDuration { - return 0 // if there's not enough time for sealing, don't wait. - } else { - // finish with margin of sealing duration before payloadTime - return remainingTime - sealingDuration - } - } else { - // if we did not yet start building, then we will schedule the start. - if remainingTime > blockTime { - // if we have too much time, then wait before starting the build - return remainingTime - blockTime - } else { - // otherwise start instantly - return 0 - } - } -} - -// BuildingOnto returns the L2 head reference that the latest block is or was being built on top of. -func (d *Sequencer) BuildingOnto() eth.L2BlockRef { - ref, _, _ := d.engine.BuildingPayload() - return ref -} - -// RunNextSequencerAction starts new block building work, or seals existing work, -// and is best timed by first awaiting the delay returned by PlanNextSequencerAction. -// If a new block is successfully sealed, it will be returned for publishing, nil otherwise. -// -// Only critical errors are bubbled up, other errors are handled internally. -// Internally starting or sealing of a block may fail with a derivation-like error: -// - If it is a critical error, the error is bubbled up to the caller. -// - If it is a reset error, the ResettableEngineControl used to build blocks is requested to reset, and a backoff applies. -// No attempt is made at completing the block building. -// - If it is a temporary error, a backoff is applied to reattempt building later. -// - If it is any other error, a backoff is applied and building is cancelled. -// -// Upon L1 reorgs that are deep enough to affect the L1 origin selection, a reset-error may occur, -// to direct the engine to follow the new L1 chain before continuing to sequence blocks. -// It is up to the EngineControl implementation to handle conflicting build jobs of the derivation -// process (as verifier) and sequencing process. -// Generally it is expected that the latest call interrupts any ongoing work, -// and the derivation process does not interrupt in the happy case, -// since it can consolidate previously sequenced blocks by comparing sequenced inputs with derived inputs. -// If the derivation pipeline does force a conflicting block, then an ongoing sequencer task might still finish, -// but the derivation can continue to reset until the chain is correct. -// If the engine is currently building safe blocks, then that building is not interrupted, and sequencing is delayed. -func (d *Sequencer) RunNextSequencerAction(ctx context.Context, agossip async.AsyncGossiper, sequencerConductor conductor.SequencerConductor) (*eth.ExecutionPayloadEnvelope, error) { - // if the engine returns a non-empty payload, OR if the async gossiper already has a payload, we can CompleteBuildingBlock - if onto, buildingID, safe := d.engine.BuildingPayload(); buildingID != (eth.PayloadID{}) || agossip.Get() != nil { - if safe { - d.log.Warn("avoiding sequencing to not interrupt safe-head changes", "onto", onto, "onto_time", onto.Time) - // approximates the worst-case time it takes to build a block, to reattempt sequencing after. - d.nextAction = d.timeNow().Add(time.Second * time.Duration(d.rollupCfg.BlockTime)) - return nil, nil - } - envelope, err := d.CompleteBuildingBlock(ctx, agossip, sequencerConductor) - if err != nil { - if errors.Is(err, derive.ErrCritical) { - return nil, err // bubble up critical errors. - } else if errors.Is(err, derive.ErrReset) { - d.log.Error("sequencer failed to seal new block, requiring derivation reset", "err", err) - d.metrics.RecordSequencerReset() - d.nextAction = d.timeNow().Add(time.Second * time.Duration(d.rollupCfg.BlockTime)) // hold off from sequencing for a full block - d.CancelBuildingBlock(ctx) - return nil, err - } else if errors.Is(err, derive.ErrTemporary) { - d.log.Error("sequencer failed temporarily to seal new block", "err", err) - d.nextAction = d.timeNow().Add(time.Second) - // We don't explicitly cancel block building jobs upon temporary errors: we may still finish the block. - // Any unfinished block building work eventually times out, and will be cleaned up that way. - } else { - d.log.Error("sequencer failed to seal block with unclassified error", "err", err) - d.nextAction = d.timeNow().Add(time.Second) - d.CancelBuildingBlock(ctx) - } - return nil, nil - } else { - payload := envelope.ExecutionPayload - d.log.Info("sequencer successfully built a new block", "block", payload.ID(), "time", uint64(payload.Timestamp), "txs", len(payload.Transactions)) - return envelope, nil - } - } else { - err := d.StartBuildingBlock(ctx) - if err != nil { - if errors.Is(err, derive.ErrCritical) { - return nil, err - } else if errors.Is(err, derive.ErrReset) { - d.log.Error("sequencer failed to seal new block, requiring derivation reset", "err", err) - d.metrics.RecordSequencerReset() - d.nextAction = d.timeNow().Add(time.Second * time.Duration(d.rollupCfg.BlockTime)) // hold off from sequencing for a full block - return nil, err - } else if errors.Is(err, derive.ErrTemporary) { - d.log.Error("sequencer temporarily failed to start building new block", "err", err) - d.nextAction = d.timeNow().Add(time.Second) - } else { - d.log.Error("sequencer failed to start building new block with unclassified error", "err", err) - d.nextAction = d.timeNow().Add(time.Second) - } - } else { - parent, buildingID, _ := d.engine.BuildingPayload() // we should have a new payload ID now that we're building a block - d.log.Info("sequencer started building new block", "payload_id", buildingID, "l2_parent_block", parent, "l2_parent_block_time", parent.Time) - } - return nil, nil - } -} diff --git a/op-node/rollup/driver/sequencer_test.go b/op-node/rollup/driver/sequencer_test.go deleted file mode 100644 index ffd5f15d9e2cc..0000000000000 --- a/op-node/rollup/driver/sequencer_test.go +++ /dev/null @@ -1,381 +0,0 @@ -package driver - -import ( - "context" - crand "crypto/rand" - "encoding/binary" - "errors" - "fmt" - "math/big" - "math/rand" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/log" - "github.com/stretchr/testify/require" - - "github.com/ethereum-optimism/optimism/op-node/metrics" - "github.com/ethereum-optimism/optimism/op-node/rollup" - "github.com/ethereum-optimism/optimism/op-node/rollup/async" - "github.com/ethereum-optimism/optimism/op-node/rollup/conductor" - "github.com/ethereum-optimism/optimism/op-node/rollup/derive" - "github.com/ethereum-optimism/optimism/op-node/rollup/engine" - "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/testlog" - "github.com/ethereum-optimism/optimism/op-service/testutils" -) - -var mockResetErr = fmt.Errorf("mock reset err: %w", derive.ErrReset) - -type FakeEngineControl struct { - finalized eth.L2BlockRef - safe eth.L2BlockRef - unsafe eth.L2BlockRef - - buildingOnto eth.L2BlockRef - buildingID eth.PayloadID - buildingSafe bool - - buildingAttrs *eth.PayloadAttributes - buildingStart time.Time - - cfg *rollup.Config - - timeNow func() time.Time - - makePayload func(onto eth.L2BlockRef, attrs *eth.PayloadAttributes) *eth.ExecutionPayload - - errTyp engine.BlockInsertionErrType - err error - - totalBuildingTime time.Duration - totalBuiltBlocks int - totalTxs int -} - -func (m *FakeEngineControl) avgBuildingTime() time.Duration { - return m.totalBuildingTime / time.Duration(m.totalBuiltBlocks) -} - -func (m *FakeEngineControl) avgTxsPerBlock() float64 { - return float64(m.totalTxs) / float64(m.totalBuiltBlocks) -} - -func (m *FakeEngineControl) StartPayload(ctx context.Context, parent eth.L2BlockRef, attrs *derive.AttributesWithParent, updateSafe bool) (errType engine.BlockInsertionErrType, err error) { - if m.err != nil { - return m.errTyp, m.err - } - m.buildingID = eth.PayloadID{} - _, _ = crand.Read(m.buildingID[:]) - m.buildingOnto = parent - m.buildingSafe = updateSafe - m.buildingAttrs = attrs.Attributes - m.buildingStart = m.timeNow() - return engine.BlockInsertOK, nil -} - -func (m *FakeEngineControl) ConfirmPayload(ctx context.Context, agossip async.AsyncGossiper, sequencerConductor conductor.SequencerConductor) (out *eth.ExecutionPayloadEnvelope, errTyp engine.BlockInsertionErrType, err error) { - if m.err != nil { - return nil, m.errTyp, m.err - } - buildTime := m.timeNow().Sub(m.buildingStart) - m.totalBuildingTime += buildTime - m.totalBuiltBlocks += 1 - payload := m.makePayload(m.buildingOnto, m.buildingAttrs) - ref, err := derive.PayloadToBlockRef(m.cfg, payload) - if err != nil { - panic(err) - } - m.unsafe = ref - if m.buildingSafe { - m.safe = ref - } - - m.resetBuildingState() - m.totalTxs += len(payload.Transactions) - return ð.ExecutionPayloadEnvelope{ExecutionPayload: payload}, engine.BlockInsertOK, nil -} - -func (m *FakeEngineControl) CancelPayload(ctx context.Context, force bool) error { - if force { - m.resetBuildingState() - } - return m.err -} - -func (m *FakeEngineControl) BuildingPayload() (onto eth.L2BlockRef, id eth.PayloadID, safe bool) { - return m.buildingOnto, m.buildingID, m.buildingSafe -} - -func (m *FakeEngineControl) Finalized() eth.L2BlockRef { - return m.finalized -} - -func (m *FakeEngineControl) UnsafeL2Head() eth.L2BlockRef { - return m.unsafe -} - -func (m *FakeEngineControl) SafeL2Head() eth.L2BlockRef { - return m.safe -} - -func (m *FakeEngineControl) resetBuildingState() { - m.buildingID = eth.PayloadID{} - m.buildingOnto = eth.L2BlockRef{} - m.buildingSafe = false - m.buildingAttrs = nil -} - -var _ engine.EngineControl = (*FakeEngineControl)(nil) - -type testAttrBuilderFn func(ctx context.Context, l2Parent eth.L2BlockRef, epoch eth.BlockID) (attrs *eth.PayloadAttributes, err error) - -func (fn testAttrBuilderFn) PreparePayloadAttributes(ctx context.Context, l2Parent eth.L2BlockRef, epoch eth.BlockID) (attrs *eth.PayloadAttributes, err error) { - return fn(ctx, l2Parent, epoch) -} - -var _ derive.AttributesBuilder = (testAttrBuilderFn)(nil) - -type testOriginSelectorFn func(ctx context.Context, l2Head eth.L2BlockRef) (eth.L1BlockRef, error) - -func (fn testOriginSelectorFn) FindL1Origin(ctx context.Context, l2Head eth.L2BlockRef) (eth.L1BlockRef, error) { - return fn(ctx, l2Head) -} - -var _ L1OriginSelectorIface = (testOriginSelectorFn)(nil) - -// TestSequencerChaosMonkey runs the sequencer in a mocked adversarial environment with -// repeated random errors in dependencies and poor clock timing. -// At the end the health of the chain is checked to show that the sequencer kept the chain in shape. -func TestSequencerChaosMonkey(t *testing.T) { - mockL1Hash := func(num uint64) (out common.Hash) { - out[31] = 1 - binary.BigEndian.PutUint64(out[:], num) - return - } - mockL2Hash := func(num uint64) (out common.Hash) { - out[31] = 2 - binary.BigEndian.PutUint64(out[:], num) - return - } - mockL1ID := func(num uint64) eth.BlockID { - return eth.BlockID{Hash: mockL1Hash(num), Number: num} - } - mockL2ID := func(num uint64) eth.BlockID { - return eth.BlockID{Hash: mockL2Hash(num), Number: num} - } - - rng := rand.New(rand.NewSource(12345)) - - l1Time := uint64(100000) - - // mute errors. We expect a lot of the mocked errors to cause error-logs. We check chain health at the end of the test. - log := testlog.Logger(t, log.LevelCrit) - - cfg := &rollup.Config{ - Genesis: rollup.Genesis{ - L1: mockL1ID(100000), - L2: mockL2ID(200000), - L2Time: l1Time + 300, // L2 may start with a relative old L1 origin and will have to catch it up - SystemConfig: eth.SystemConfig{}, - }, - BlockTime: 2, - MaxSequencerDrift: 30, - } - // keep track of the L1 timestamps we mock because sometimes we only have the L1 hash/num handy - l1Times := map[eth.BlockID]uint64{cfg.Genesis.L1: l1Time} - - genesisL2 := eth.L2BlockRef{ - Hash: cfg.Genesis.L2.Hash, - Number: cfg.Genesis.L2.Number, - ParentHash: mockL2Hash(cfg.Genesis.L2.Number - 1), - Time: cfg.Genesis.L2Time, - L1Origin: cfg.Genesis.L1, - SequenceNumber: 0, - } - // initialize our engine state - engControl := &FakeEngineControl{ - finalized: genesisL2, - safe: genesisL2, - unsafe: genesisL2, - cfg: cfg, - } - - // start wallclock at 5 minutes after the current L2 head. The sequencer has some catching up to do! - clockTime := time.Unix(int64(engControl.unsafe.Time)+5*60, 0) - clockFn := func() time.Time { - return clockTime - } - engControl.timeNow = clockFn - - // mock payload building, we don't need to process any real txs. - engControl.makePayload = func(onto eth.L2BlockRef, attrs *eth.PayloadAttributes) *eth.ExecutionPayload { - txs := make([]eth.Data, 0) - txs = append(txs, attrs.Transactions...) // include deposits - if !attrs.NoTxPool { // if we are allowed to sequence from tx pool, mock some txs - n := rng.Intn(20) - for i := 0; i < n; i++ { - txs = append(txs, []byte(fmt.Sprintf("mock sequenced tx %d", i))) - } - } - return ð.ExecutionPayload{ - ParentHash: onto.Hash, - BlockNumber: eth.Uint64Quantity(onto.Number) + 1, - Timestamp: attrs.Timestamp, - BlockHash: mockL2Hash(onto.Number), - Transactions: txs, - } - } - - // We keep attribute building simple, we don't talk to a real execution engine in this test. - // Sometimes we fake an error in the attributes preparation. - var attrsErr error - attrBuilder := testAttrBuilderFn(func(ctx context.Context, l2Parent eth.L2BlockRef, epoch eth.BlockID) (attrs *eth.PayloadAttributes, err error) { - if attrsErr != nil { - return nil, attrsErr - } - seqNr := l2Parent.SequenceNumber + 1 - if epoch != l2Parent.L1Origin { - seqNr = 0 - } - l1Info := &testutils.MockBlockInfo{ - InfoHash: epoch.Hash, - InfoParentHash: mockL1Hash(epoch.Number - 1), - InfoCoinbase: common.Address{}, - InfoRoot: common.Hash{}, - InfoNum: epoch.Number, - InfoTime: l1Times[epoch], - InfoMixDigest: [32]byte{}, - InfoBaseFee: big.NewInt(1234), - InfoReceiptRoot: common.Hash{}, - } - infoDep, err := derive.L1InfoDepositBytes(cfg, cfg.Genesis.SystemConfig, seqNr, l1Info, 0) - require.NoError(t, err) - - testGasLimit := eth.Uint64Quantity(10_000_000) - return ð.PayloadAttributes{ - Timestamp: eth.Uint64Quantity(l2Parent.Time + cfg.BlockTime), - PrevRandao: eth.Bytes32{}, - SuggestedFeeRecipient: common.Address{}, - Transactions: []eth.Data{infoDep}, - NoTxPool: false, - GasLimit: &testGasLimit, - }, nil - }) - - maxL1BlockTimeGap := uint64(100) - // The origin selector just generates random L1 blocks based on RNG - var originErr error - originSelector := testOriginSelectorFn(func(ctx context.Context, l2Head eth.L2BlockRef) (eth.L1BlockRef, error) { - if originErr != nil { - return eth.L1BlockRef{}, originErr - } - origin := eth.L1BlockRef{ - Hash: mockL1Hash(l2Head.L1Origin.Number), - Number: l2Head.L1Origin.Number, - ParentHash: mockL1Hash(l2Head.L1Origin.Number), - Time: l1Times[l2Head.L1Origin], - } - // randomly make a L1 origin appear, if we can even select it - nextL2Time := l2Head.Time + cfg.BlockTime - if nextL2Time <= origin.Time { - return origin, nil - } - maxTimeIncrement := nextL2Time - origin.Time - if maxTimeIncrement > maxL1BlockTimeGap { - maxTimeIncrement = maxL1BlockTimeGap - } - if rng.Intn(10) == 0 { - nextOrigin := eth.L1BlockRef{ - Hash: mockL1Hash(origin.Number + 1), - Number: origin.Number + 1, - ParentHash: origin.Hash, - Time: origin.Time + 1 + uint64(rng.Int63n(int64(maxTimeIncrement))), - } - l1Times[nextOrigin.ID()] = nextOrigin.Time - return nextOrigin, nil - } else { - return origin, nil - } - }) - - seq := NewSequencer(log, cfg, engControl, attrBuilder, originSelector, metrics.NoopMetrics) - seq.timeNow = clockFn - - // try to build 1000 blocks, with 5x as many planning attempts, to handle errors and clock problems - desiredBlocks := 1000 - for i := 0; i < 5*desiredBlocks && engControl.totalBuiltBlocks < desiredBlocks; i++ { - delta := seq.PlanNextSequencerAction() - - x := rng.Float32() - if x < 0.01 { // 1%: mess a lot with the clock: simulate a hang of up to 30 seconds - if i < desiredBlocks/2 { // only in first 50% of blocks to let it heal, hangs take time - delta = time.Duration(rng.Float64() * float64(time.Second*30)) - } - } else if x < 0.1 { // 9%: mess with the timing, -50% to 50% off - delta = time.Duration((0.5 + rng.Float64()) * float64(delta)) - } else if x < 0.5 { - // 40%: mess slightly with the timing, -10% to 10% off - delta = time.Duration((0.9 + rng.Float64()*0.2) * float64(delta)) - } - clockTime = clockTime.Add(delta) - - // reset errors - originErr = nil - attrsErr = nil - if engControl.err != mockResetErr { // the mockResetErr requires the sequencer to Reset() to recover. - engControl.err = nil - } - engControl.errTyp = engine.BlockInsertOK - - // maybe make something maybe fail, or try a new L1 origin - switch rng.Intn(20) { // 9/20 = 45% chance to fail sequencer action (!!!) - case 0, 1: - originErr = errors.New("mock origin error") - case 2, 3: - attrsErr = errors.New("mock attributes error") - case 4, 5: - engControl.err = errors.New("mock temporary engine error") - engControl.errTyp = engine.BlockInsertTemporaryErr - case 6, 7: - engControl.err = errors.New("mock prestate engine error") - engControl.errTyp = engine.BlockInsertPrestateErr - case 8: - engControl.err = mockResetErr - default: - // no error - } - payload, err := seq.RunNextSequencerAction(context.Background(), async.NoOpGossiper{}, &conductor.NoOpConductor{}) - // RunNextSequencerAction passes ErrReset & ErrCritical through. - // Only suppress ErrReset, not ErrCritical - if !errors.Is(err, derive.ErrReset) { - require.NoError(t, err) - } - if payload != nil { - require.Equal(t, engControl.UnsafeL2Head().ID(), payload.ExecutionPayload.ID(), "head must stay in sync with emitted payloads") - var tx types.Transaction - require.NoError(t, tx.UnmarshalBinary(payload.ExecutionPayload.Transactions[0])) - info, err := derive.L1BlockInfoFromBytes(cfg, uint64(payload.ExecutionPayload.Timestamp), tx.Data()) - require.NoError(t, err) - require.GreaterOrEqual(t, uint64(payload.ExecutionPayload.Timestamp), info.Time, "ensure L2 time >= L1 time") - } - } - - // Now, even though: - // - the start state was behind the wallclock - // - the L1 origin was far behind the L2 - // - we made all components fail at random - // - messed with the clock - // the L2 chain was still built and stats are healthy on average! - l2Head := engControl.UnsafeL2Head() - t.Logf("avg build time: %s, clock timestamp: %d, L2 head time: %d, L1 origin time: %d, avg txs per block: %f", engControl.avgBuildingTime(), clockFn().Unix(), l2Head.Time, l1Times[l2Head.L1Origin], engControl.avgTxsPerBlock()) - require.Equal(t, engControl.totalBuiltBlocks, desiredBlocks, "persist through random errors and build the desired blocks") - require.Equal(t, l2Head.Time, cfg.Genesis.L2Time+uint64(desiredBlocks)*cfg.BlockTime, "reached desired L2 block timestamp") - require.GreaterOrEqual(t, l2Head.Time, l1Times[l2Head.L1Origin], "the L2 time >= the L1 time") - require.Less(t, l2Head.Time-l1Times[l2Head.L1Origin], uint64(100), "The L1 origin time is close to the L2 time") - require.Less(t, clockTime.Sub(time.Unix(int64(l2Head.Time), 0)).Abs(), 2*time.Second, "L2 time is accurate, within 2 seconds of wallclock") - require.Greater(t, engControl.avgBuildingTime(), time.Second, "With 2 second block time and 1 second error backoff and healthy-on-average errors, building time should at least be a second") - require.Greater(t, engControl.avgTxsPerBlock(), 3.0, "We expect at least 1 system tx per block, but with a mocked 0-10 txs we expect an higher avg") -} diff --git a/op-node/rollup/driver/state.go b/op-node/rollup/driver/state.go index 17bfb5a655664..c216134704b83 100644 --- a/op-node/rollup/driver/state.go +++ b/op-node/rollup/driver/state.go @@ -1,7 +1,6 @@ package driver import ( - "bytes" "context" "errors" "fmt" @@ -12,37 +11,31 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum-optimism/optimism/op-node/rollup" - "github.com/ethereum-optimism/optimism/op-node/rollup/async" "github.com/ethereum-optimism/optimism/op-node/rollup/clsync" - "github.com/ethereum-optimism/optimism/op-node/rollup/conductor" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-node/rollup/engine" "github.com/ethereum-optimism/optimism/op-node/rollup/event" "github.com/ethereum-optimism/optimism/op-node/rollup/finality" + "github.com/ethereum-optimism/optimism/op-node/rollup/sequencing" "github.com/ethereum-optimism/optimism/op-node/rollup/status" "github.com/ethereum-optimism/optimism/op-node/rollup/sync" "github.com/ethereum-optimism/optimism/op-service/eth" ) -var ( - ErrSequencerAlreadyStarted = errors.New("sequencer already running") - ErrSequencerAlreadyStopped = errors.New("sequencer not running") -) - // Deprecated: use eth.SyncStatus instead. type SyncStatus = eth.SyncStatus -// sealingDuration defines the expected time it takes to seal the block -const sealingDuration = time.Millisecond * 50 - type Driver struct { + eventSys event.System + statusTracker SyncStatusTracker *SyncDeriver sched *StepSchedulingDeriver - synchronousEvents event.EmitterDrainer + emitter event.Emitter + drain func() error // Requests to block the event loop for synchronous execution to avoid reading an inconsistent state stateReq chan chan struct{} @@ -51,25 +44,8 @@ type Driver struct { // It tells the caller that the reset occurred by closing the passed in channel. forceReset chan chan struct{} - // Upon receiving a hash in this channel, the sequencer is started at the given hash. - // It tells the caller that the sequencer started by closing the passed in channel (or returning an error). - startSequencer chan hashAndErrorChannel - - // Upon receiving a channel in this channel, the sequencer is stopped. - // It tells the caller that the sequencer stopped by returning the latest sequenced L2 block hash. - stopSequencer chan chan hashAndError - - // Upon receiving a channel in this channel, the current sequencer status is queried. - // It tells the caller the status by outputting a boolean to the provided channel: - // true when the sequencer is active, false when it is not. - sequencerActive chan chan bool - - // sequencerNotifs is notified when the sequencer is started or stopped - sequencerNotifs SequencerStateListener - - sequencerConductor conductor.SequencerConductor - - // Driver config: verifier and sequencer settings + // Driver config: verifier and sequencer settings. + // May not be modified after starting the Driver. driverConfig *Config // L1 Signals: @@ -85,15 +61,11 @@ type Driver struct { // Interface to signal the L2 block range to sync. altSync AltSync - // async gossiper for payloads to be gossiped without - // blocking the event loop or waiting for insertion - asyncGossiper async.AsyncGossiper - // L2 Signals: unsafeL2Payloads chan *eth.ExecutionPayloadEnvelope - sequencer SequencerIface + sequencer sequencing.SequencerIface network Network // may be nil, network for is optional metrics Metrics @@ -108,23 +80,17 @@ type Driver struct { // Start starts up the state loop. // The loop will have been started iff err is not nil. func (s *Driver) Start() error { - log.Info("Starting driver", "sequencerEnabled", s.driverConfig.SequencerEnabled, "sequencerStopped", s.driverConfig.SequencerStopped) + log.Info("Starting driver", "sequencerEnabled", s.driverConfig.SequencerEnabled, + "sequencerStopped", s.driverConfig.SequencerStopped) if s.driverConfig.SequencerEnabled { - // Notify the initial sequencer state - // This ensures persistence can write the state correctly and that the state file exists - var err error - if s.driverConfig.SequencerStopped { - err = s.sequencerNotifs.SequencerStopped() - } else { - err = s.sequencerNotifs.SequencerStarted() + if err := s.sequencer.SetMaxSafeLag(s.driverCtx, s.driverConfig.SequencerMaxSafeLag); err != nil { + return fmt.Errorf("failed to set sequencer max safe lag: %w", err) } - if err != nil { + if err := s.sequencer.Init(s.driverCtx, !s.driverConfig.SequencerStopped); err != nil { return fmt.Errorf("persist initial sequencer state: %w", err) } } - s.asyncGossiper.Start() - s.wg.Add(1) go s.eventLoop() @@ -134,8 +100,8 @@ func (s *Driver) Start() error { func (s *Driver) Close() error { s.driverCancel() s.wg.Wait() - s.asyncGossiper.Stop() - s.sequencerConductor.Close() + s.eventSys.Stop() + s.sequencer.Close() return nil } @@ -189,7 +155,7 @@ func (s *Driver) eventLoop() { // reqStep requests a derivation step nicely, with a delay if this is a reattempt, or not at all if we already scheduled a reattempt. reqStep := func() { - s.Emit(StepReqEvent{}) + s.emitter.Emit(StepReqEvent{}) } // We call reqStep right away to finish syncing to the tip of the chain if we're behind. @@ -199,13 +165,31 @@ func (s *Driver) eventLoop() { sequencerTimer := time.NewTimer(0) var sequencerCh <-chan time.Time + var prevTime time.Time + // planSequencerAction updates the sequencerTimer with the next action, if any. + // The sequencerCh is nil (indefinitely blocks on read) if no action needs to be performed, + // or set to the timer channel if there is an action scheduled. planSequencerAction := func() { - delay := s.sequencer.PlanNextSequencerAction() + nextAction, ok := s.sequencer.NextAction() + if !ok { + if sequencerCh != nil { + s.log.Info("Sequencer paused until new events") + } + sequencerCh = nil + return + } + // avoid unnecessary timer resets + if nextAction == prevTime { + return + } + prevTime = nextAction sequencerCh = sequencerTimer.C if len(sequencerCh) > 0 { // empty if not already drained before resetting <-sequencerCh } - sequencerTimer.Reset(delay) + delta := time.Until(nextAction) + s.log.Info("Scheduled sequencer action", "delta", delta) + sequencerTimer.Reset(delta) } // Create a ticker to check if there is a gap in the engine queue. Whenever @@ -220,42 +204,19 @@ func (s *Driver) eventLoop() { return } - // While event-processing is synchronous we have to drain - // (i.e. process all queued-up events) before creating any new events. - if err := s.synchronousEvents.Drain(); err != nil { - if s.driverCtx.Err() != nil { - return - } - s.log.Error("unexpected error from event-draining", "err", err) - } - - // If we are sequencing, and the L1 state is ready, update the trigger for the next sequencer action. - // This may adjust at any time based on fork-choice changes or previous errors. - // And avoid sequencing if the derivation pipeline indicates the engine is not ready. - if s.driverConfig.SequencerEnabled && !s.driverConfig.SequencerStopped && - s.statusTracker.L1Head() != (eth.L1BlockRef{}) && s.Derivation.DerivationReady() { - if s.driverConfig.SequencerMaxSafeLag > 0 && s.Engine.SafeL2Head().Number+s.driverConfig.SequencerMaxSafeLag <= s.Engine.UnsafeL2Head().Number { - // If the safe head has fallen behind by a significant number of blocks, delay creating new blocks - // until the safe lag is below SequencerMaxSafeLag. - if sequencerCh != nil { - s.log.Warn( - "Delay creating new block since safe lag exceeds limit", - "safe_l2", s.Engine.SafeL2Head(), - "unsafe_l2", s.Engine.UnsafeL2Head(), - ) - sequencerCh = nil + if s.drain != nil { + // While event-processing is synchronous we have to drain + // (i.e. process all queued-up events) before creating any new events. + if err := s.drain(); err != nil { + if s.driverCtx.Err() != nil { + return } - } else if s.sequencer.BuildingOnto().ID() != s.Engine.UnsafeL2Head().ID() { - // If we are sequencing, and the L1 state is ready, update the trigger for the next sequencer action. - // This may adjust at any time based on fork-choice changes or previous errors. - // - // update sequencer time if the head changed - planSequencerAction() + s.log.Error("unexpected error from event-draining", "err", err) } - } else { - sequencerCh = nil } + planSequencerAction() + // If the engine is not ready, or if the L2 head is actively changing, then reset the alt-sync: // there is no need to request L2 blocks when we are syncing already. if head := s.Engine.UnsafeL2Head(); head != lastUnsafeL2 || !s.Derivation.DerivationReady() { @@ -265,16 +226,7 @@ func (s *Driver) eventLoop() { select { case <-sequencerCh: - // the payload publishing is handled by the async gossiper, which will begin gossiping as soon as available - // so, we don't need to receive the payload here - _, err := s.sequencer.RunNextSequencerAction(s.driverCtx, s.asyncGossiper, s.sequencerConductor) - if errors.Is(err, derive.ErrReset) { - s.Emitter.Emit(rollup.ResetEvent{}) - } else if err != nil { - s.log.Error("Sequencer critical error", "err", err) - return - } - planSequencerAction() // schedule the next sequencer action to keep the sequencing looping + s.Emitter.Emit(sequencing.SequencerActionEvent{}) case <-altSyncTicker.C: // Check if there is a gap in the current unsafe payload queue. ctx, cancel := context.WithTimeout(s.driverCtx, time.Second*2) @@ -311,12 +263,12 @@ func (s *Driver) eventLoop() { s.Emitter.Emit(status.L1SafeEvent{L1Safe: newL1Safe}) // no step, justified L1 information does not do anything for L2 derivation or status case newL1Finalized := <-s.l1FinalizedSig: - s.Emit(finality.FinalizeL1Event{FinalizedL1: newL1Finalized}) + s.emitter.Emit(finality.FinalizeL1Event{FinalizedL1: newL1Finalized}) reqStep() // we may be able to mark more L2 data as finalized now case <-s.sched.NextDelayedStep(): - s.Emit(StepAttemptEvent{}) + s.emitter.Emit(StepAttemptEvent{}) case <-s.sched.NextStep(): - s.Emit(StepAttemptEvent{}) + s.emitter.Emit(StepAttemptEvent{}) case respCh := <-s.stateReq: respCh <- struct{}{} case respCh := <-s.forceReset: @@ -324,39 +276,6 @@ func (s *Driver) eventLoop() { s.Derivation.Reset() s.metrics.RecordPipelineReset() close(respCh) - case resp := <-s.startSequencer: - unsafeHead := s.Engine.UnsafeL2Head().Hash - if !s.driverConfig.SequencerStopped { - resp.err <- ErrSequencerAlreadyStarted - } else if !bytes.Equal(unsafeHead[:], resp.hash[:]) { - resp.err <- fmt.Errorf("block hash does not match: head %s, received %s", unsafeHead.String(), resp.hash.String()) - } else { - if err := s.sequencerNotifs.SequencerStarted(); err != nil { - resp.err <- fmt.Errorf("sequencer start notification: %w", err) - continue - } - s.log.Info("Sequencer has been started") - s.driverConfig.SequencerStopped = false - close(resp.err) - planSequencerAction() // resume sequencing - } - case respCh := <-s.stopSequencer: - if s.driverConfig.SequencerStopped { - respCh <- hashAndError{err: ErrSequencerAlreadyStopped} - } else { - if err := s.sequencerNotifs.SequencerStopped(); err != nil { - respCh <- hashAndError{err: fmt.Errorf("sequencer start notification: %w", err)} - continue - } - s.log.Warn("Sequencer has been stopped") - s.driverConfig.SequencerStopped = true - // Cancel any inflight block building. If we don't cancel this, we can resume sequencing an old block - // even if we've received new unsafe heads in the interim, causing us to introduce a re-org. - s.sequencer.CancelBuildingBlock(s.driverCtx) - respCh <- hashAndError{hash: s.Engine.UnsafeL2Head().Hash} - } - case respCh := <-s.sequencerActive: - respCh <- !s.driverConfig.SequencerStopped case <-s.driverCtx.Done(): return } @@ -366,7 +285,7 @@ func (s *Driver) eventLoop() { // OnEvent handles broadcasted events. // The Driver itself is a deriver to catch system-critical events. // Other event-handling should be encapsulated into standalone derivers. -func (s *Driver) OnEvent(ev event.Event) { +func (s *Driver) OnEvent(ev event.Event) bool { switch x := ev.(type) { case rollup.CriticalErrorEvent: s.Log.Error("Derivation process critical error", "err", x.Err) @@ -378,21 +297,17 @@ func (s *Driver) OnEvent(ev event.Event) { logger.Error("Failed to shutdown driver on critical error", "err", err) } }() - return + return true + default: + return false } } -func (s *Driver) Emit(ev event.Event) { - s.synchronousEvents.Emit(ev) -} - type SyncDeriver struct { // The derivation pipeline is reset whenever we reorg. // The derivation pipeline determines the new l2Safe. Derivation DerivationPipeline - Finalizer Finalizer - SafeHeadNotifs rollup.SafeHeadListener // notified when safe head is updated CLSync CLSync @@ -418,7 +333,11 @@ type SyncDeriver struct { Drain func() error } -func (s *SyncDeriver) OnEvent(ev event.Event) { +func (s *SyncDeriver) AttachEmitter(em event.Emitter) { + s.Emitter = em +} + +func (s *SyncDeriver) OnEvent(ev event.Event) bool { switch x := ev.(type) { case StepEvent: s.onStepEvent() @@ -429,10 +348,8 @@ func (s *SyncDeriver) OnEvent(ev event.Event) { s.Emitter.Emit(StepReqEvent{}) case rollup.EngineTemporaryErrorEvent: s.Log.Warn("Engine temporary error", "err", x.Err) - // Make sure that for any temporarily failed attributes we retry processing. - s.Emitter.Emit(engine.PendingSafeRequestEvent{}) - + // This will be triggered by a step. After appropriate backoff. s.Emitter.Emit(StepReqEvent{}) case engine.EngineResetConfirmedEvent: s.onEngineConfirmedReset(x) @@ -446,7 +363,10 @@ func (s *SyncDeriver) OnEvent(ev event.Event) { s.Emitter.Emit(StepReqEvent{ResetBackoff: true}) case engine.SafeDerivedEvent: s.onSafeDerivedBlock(x) + default: + return false } + return true } func (s *SyncDeriver) onSafeDerivedBlock(x engine.SafeDerivedEvent) { @@ -574,69 +494,19 @@ func (s *Driver) ResetDerivationPipeline(ctx context.Context) error { } func (s *Driver) StartSequencer(ctx context.Context, blockHash common.Hash) error { - if !s.driverConfig.SequencerEnabled { - return errors.New("sequencer is not enabled") - } - if isLeader, err := s.sequencerConductor.Leader(ctx); err != nil { - return fmt.Errorf("sequencer leader check failed: %w", err) - } else if !isLeader { - return errors.New("sequencer is not the leader, aborting.") - } - h := hashAndErrorChannel{ - hash: blockHash, - err: make(chan error, 1), - } - select { - case <-ctx.Done(): - return ctx.Err() - case s.startSequencer <- h: - select { - case <-ctx.Done(): - return ctx.Err() - case e := <-h.err: - return e - } - } + return s.sequencer.Start(ctx, blockHash) } func (s *Driver) StopSequencer(ctx context.Context) (common.Hash, error) { - if !s.driverConfig.SequencerEnabled { - return common.Hash{}, errors.New("sequencer is not enabled") - } - respCh := make(chan hashAndError, 1) - select { - case <-ctx.Done(): - return common.Hash{}, ctx.Err() - case s.stopSequencer <- respCh: - select { - case <-ctx.Done(): - return common.Hash{}, ctx.Err() - case he := <-respCh: - return he.hash, he.err - } - } + return s.sequencer.Stop(ctx) } func (s *Driver) SequencerActive(ctx context.Context) (bool, error) { - if !s.driverConfig.SequencerEnabled { - return false, nil - } - respCh := make(chan bool, 1) - select { - case <-ctx.Done(): - return false, ctx.Err() - case s.sequencerActive <- respCh: - select { - case <-ctx.Done(): - return false, ctx.Err() - case active := <-respCh: - return active, nil - } - } + return s.sequencer.Active(), nil } func (s *Driver) OverrideLeader(ctx context.Context) error { - return s.sequencerConductor.OverrideLeader(ctx) + return s.sequencer.OverrideLeader(ctx) } // SyncStatus blocks the driver event loop and captures the syncing status. @@ -660,16 +530,6 @@ func (s *Driver) BlockRefWithStatus(ctx context.Context, num uint64) (eth.L2Bloc } } -type hashAndError struct { - hash common.Hash - err error -} - -type hashAndErrorChannel struct { - hash common.Hash - err chan error -} - // checkForGapInUnsafeQueue checks if there is a gap in the unsafe queue and attempts to retrieve the missing payloads from an alt-sync method. // WARNING: This is only an outgoing signal, the blocks are not guaranteed to be retrieved. // Results are received through OnUnsafeL2Payload. diff --git a/op-node/rollup/driver/steps.go b/op-node/rollup/driver/steps.go index 7628584f003e7..0afe959412497 100644 --- a/op-node/rollup/driver/steps.go +++ b/op-node/rollup/driver/steps.go @@ -72,17 +72,20 @@ type StepSchedulingDeriver struct { emitter event.Emitter } -func NewStepSchedulingDeriver(log log.Logger, emitter event.Emitter) *StepSchedulingDeriver { +func NewStepSchedulingDeriver(log log.Logger) *StepSchedulingDeriver { return &StepSchedulingDeriver{ stepAttempts: 0, bOffStrategy: retry.Exponential(), stepReqCh: make(chan struct{}, 1), delayedStepReq: nil, log: log, - emitter: emitter, } } +func (s *StepSchedulingDeriver) AttachEmitter(em event.Emitter) { + s.emitter = em +} + // NextStep is a channel to await, and if triggered, // the caller should emit a StepAttemptEvent to queue up a step while maintaining backoff. func (s *StepSchedulingDeriver) NextStep() <-chan struct{} { @@ -96,7 +99,7 @@ func (s *StepSchedulingDeriver) NextDelayedStep() <-chan time.Time { return s.delayedStepReq } -func (s *StepSchedulingDeriver) OnEvent(ev event.Event) { +func (s *StepSchedulingDeriver) OnEvent(ev event.Event) bool { step := func() { s.delayedStepReq = nil select { @@ -138,5 +141,8 @@ func (s *StepSchedulingDeriver) OnEvent(ev event.Event) { s.emitter.Emit(StepEvent{}) case ResetStepBackoffEvent: s.stepAttempts = 0 + default: + return false } + return true } diff --git a/op-node/rollup/driver/steps_test.go b/op-node/rollup/driver/steps_test.go index 764b00152829d..7deac6636562d 100644 --- a/op-node/rollup/driver/steps_test.go +++ b/op-node/rollup/driver/steps_test.go @@ -17,7 +17,8 @@ func TestStepSchedulingDeriver(t *testing.T) { emitter := event.EmitterFunc(func(ev event.Event) { queued = append(queued, ev) }) - sched := NewStepSchedulingDeriver(logger, emitter) + sched := NewStepSchedulingDeriver(logger) + sched.AttachEmitter(emitter) require.Len(t, sched.NextStep(), 0, "start empty") sched.OnEvent(StepReqEvent{}) require.Len(t, sched.NextStep(), 1, "take request") diff --git a/op-node/rollup/engine/build_cancel.go b/op-node/rollup/engine/build_cancel.go new file mode 100644 index 0000000000000..7c9995c28e854 --- /dev/null +++ b/op-node/rollup/engine/build_cancel.go @@ -0,0 +1,34 @@ +package engine + +import ( + "context" + + "github.com/ethereum-optimism/optimism/op-node/rollup" + "github.com/ethereum-optimism/optimism/op-service/eth" +) + +type BuildCancelEvent struct { + Info eth.PayloadInfo + Force bool +} + +func (ev BuildCancelEvent) String() string { + return "build-cancel" +} + +func (eq *EngDeriver) onBuildCancel(ev BuildCancelEvent) { + ctx, cancel := context.WithTimeout(eq.ctx, buildCancelTimeout) + defer cancel() + // the building job gets wrapped up as soon as the payload is retrieved, there's no explicit cancel in the Engine API + eq.log.Warn("cancelling old block building job", "info", ev.Info) + _, err := eq.ec.engine.GetPayload(ctx, ev.Info) + if err != nil { + if x, ok := err.(eth.InputError); ok && x.Code == eth.UnknownPayload { //nolint:all + return // if unknown, then it did not need to be cancelled anymore. + } + eq.log.Error("failed to cancel block building job", "info", ev.Info, "err", err) + if !ev.Force { + eq.emitter.Emit(rollup.EngineTemporaryErrorEvent{Err: err}) + } + } +} diff --git a/op-node/rollup/engine/build_invalid.go b/op-node/rollup/engine/build_invalid.go new file mode 100644 index 0000000000000..e684f2de2eade --- /dev/null +++ b/op-node/rollup/engine/build_invalid.go @@ -0,0 +1,63 @@ +package engine + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/core/types" + + "github.com/ethereum-optimism/optimism/op-node/rollup" + "github.com/ethereum-optimism/optimism/op-node/rollup/derive" +) + +// BuildInvalidEvent is an internal engine event, to post-process upon invalid attributes. +// Not for temporary processing problems. +type BuildInvalidEvent struct { + Attributes *derive.AttributesWithParent + Err error +} + +func (ev BuildInvalidEvent) String() string { + return "build-invalid" +} + +// InvalidPayloadAttributesEvent is a signal to external derivers that the attributes were invalid. +type InvalidPayloadAttributesEvent struct { + Attributes *derive.AttributesWithParent + Err error +} + +func (ev InvalidPayloadAttributesEvent) String() string { + return "invalid-payload-attributes" +} + +func (eq *EngDeriver) onBuildInvalid(ev BuildInvalidEvent) { + eq.log.Warn("could not process payload attributes", "err", ev.Err) + + // Count the number of deposits to see if the tx list is deposit only. + depositCount := 0 + for _, tx := range ev.Attributes.Attributes.Transactions { + if len(tx) > 0 && tx[0] == types.DepositTxType { + depositCount += 1 + } + } + // Deposit transaction execution errors are suppressed in the execution engine, but if the + // block is somehow invalid, there is nothing we can do to recover & we should exit. + if len(ev.Attributes.Attributes.Transactions) == depositCount { + eq.log.Error("deposit only block was invalid", "parent", ev.Attributes.Parent, "err", ev.Err) + eq.emitter.Emit(rollup.CriticalErrorEvent{Err: fmt.Errorf("failed to process block with only deposit transactions: %w", ev.Err)}) + return + } + // Revert the pending safe head to the safe head. + eq.ec.SetPendingSafeL2Head(eq.ec.SafeL2Head()) + // suppress the error b/c we want to retry with the next batch from the batch queue + // If there is no valid batch the node will eventually force a deposit only block. If + // the deposit only block fails, this will return the critical error above. + + // Try to restore to previous known unsafe chain. + eq.ec.SetBackupUnsafeL2Head(eq.ec.BackupUnsafeL2Head(), true) + + // drop the payload without inserting it into the engine + + // Signal that we deemed the attributes as unfit + eq.emitter.Emit(InvalidPayloadAttributesEvent(ev)) +} diff --git a/op-node/rollup/engine/build_seal.go b/op-node/rollup/engine/build_seal.go new file mode 100644 index 0000000000000..a5c72c74fdb76 --- /dev/null +++ b/op-node/rollup/engine/build_seal.go @@ -0,0 +1,121 @@ +package engine + +import ( + "context" + "fmt" + "time" + + "github.com/ethereum-optimism/optimism/op-node/rollup/derive" + "github.com/ethereum-optimism/optimism/op-service/eth" +) + +// PayloadSealInvalidEvent identifies a permanent in-consensus problem with the payload sealing. +type PayloadSealInvalidEvent struct { + Info eth.PayloadInfo + Err error + + IsLastInSpan bool + DerivedFrom eth.L1BlockRef +} + +func (ev PayloadSealInvalidEvent) String() string { + return "payload-seal-invalid" +} + +// PayloadSealExpiredErrorEvent identifies a form of failed payload-sealing that is not coupled +// to the attributes themselves, but rather the build-job process. +// The user should re-attempt by starting a new build process. The payload-sealing job should not be re-attempted, +// as it most likely expired, timed out, or referenced an otherwise invalidated block-building job identifier. +type PayloadSealExpiredErrorEvent struct { + Info eth.PayloadInfo + Err error + + IsLastInSpan bool + DerivedFrom eth.L1BlockRef +} + +func (ev PayloadSealExpiredErrorEvent) String() string { + return "payload-seal-expired-error" +} + +type BuildSealEvent struct { + Info eth.PayloadInfo + BuildStarted time.Time + // if payload should be promoted to safe (must also be pending safe, see DerivedFrom) + IsLastInSpan bool + // payload is promoted to pending-safe if non-zero + DerivedFrom eth.L1BlockRef +} + +func (ev BuildSealEvent) String() string { + return "build-seal" +} + +func (eq *EngDeriver) onBuildSeal(ev BuildSealEvent) { + ctx, cancel := context.WithTimeout(eq.ctx, buildSealTimeout) + defer cancel() + + sealingStart := time.Now() + envelope, err := eq.ec.engine.GetPayload(ctx, ev.Info) + if err != nil { + if x, ok := err.(eth.InputError); ok && x.Code == eth.UnknownPayload { //nolint:all + eq.log.Warn("Cannot seal block, payload ID is unknown", + "payloadID", ev.Info.ID, "payload_time", ev.Info.Timestamp, + "started_time", ev.BuildStarted) + } + // Although the engine will very likely not be able to continue from here with the same building job, + // we still call it "temporary", since the exact same payload-attributes have not been invalidated in-consensus. + // So the user (attributes-handler or sequencer) should be able to re-attempt the exact + // same attributes with a new block-building job from here to recover from this error. + // We name it "expired", as this generally identifies a timeout, unknown job, or otherwise invalidated work. + eq.emitter.Emit(PayloadSealExpiredErrorEvent{ + Info: ev.Info, + Err: fmt.Errorf("failed to seal execution payload (ID: %s): %w", ev.Info.ID, err), + IsLastInSpan: ev.IsLastInSpan, + DerivedFrom: ev.DerivedFrom, + }) + return + } + + if err := sanityCheckPayload(envelope.ExecutionPayload); err != nil { + eq.emitter.Emit(PayloadSealInvalidEvent{ + Info: ev.Info, + Err: fmt.Errorf("failed sanity-check of execution payload contents (ID: %s, blockhash: %s): %w", + ev.Info.ID, envelope.ExecutionPayload.BlockHash, err), + IsLastInSpan: ev.IsLastInSpan, + DerivedFrom: ev.DerivedFrom, + }) + return + } + + ref, err := derive.PayloadToBlockRef(eq.cfg, envelope.ExecutionPayload) + if err != nil { + eq.emitter.Emit(PayloadSealInvalidEvent{ + Info: ev.Info, + Err: fmt.Errorf("failed to decode L2 block ref from payload: %w", err), + IsLastInSpan: ev.IsLastInSpan, + DerivedFrom: ev.DerivedFrom, + }) + return + } + + now := time.Now() + sealTime := now.Sub(sealingStart) + buildTime := now.Sub(ev.BuildStarted) + eq.metrics.RecordSequencerSealingTime(sealTime) + eq.metrics.RecordSequencerBuildingDiffTime(buildTime - time.Duration(eq.cfg.BlockTime)*time.Second) + + txnCount := len(envelope.ExecutionPayload.Transactions) + eq.metrics.CountSequencedTxs(txnCount) + + eq.log.Debug("Processed new L2 block", "l2_unsafe", ref, "l1_origin", ref.L1Origin, + "txs", txnCount, "time", ref.Time, "seal_time", sealTime, "build_time", buildTime) + + eq.emitter.Emit(BuildSealedEvent{ + IsLastInSpan: ev.IsLastInSpan, + DerivedFrom: ev.DerivedFrom, + Info: ev.Info, + Envelope: envelope, + Ref: ref, + }) +} diff --git a/op-node/rollup/engine/build_sealed.go b/op-node/rollup/engine/build_sealed.go new file mode 100644 index 0000000000000..d588d77b7f223 --- /dev/null +++ b/op-node/rollup/engine/build_sealed.go @@ -0,0 +1,34 @@ +package engine + +import ( + "github.com/ethereum-optimism/optimism/op-service/eth" +) + +// BuildSealedEvent is emitted by the engine when a payload finished building, +// but is not locally inserted as canonical block yet +type BuildSealedEvent struct { + // if payload should be promoted to safe (must also be pending safe, see DerivedFrom) + IsLastInSpan bool + // payload is promoted to pending-safe if non-zero + DerivedFrom eth.L1BlockRef + + Info eth.PayloadInfo + Envelope *eth.ExecutionPayloadEnvelope + Ref eth.L2BlockRef +} + +func (ev BuildSealedEvent) String() string { + return "build-sealed" +} + +func (eq *EngDeriver) onBuildSealed(ev BuildSealedEvent) { + // If a (pending) safe block, immediately process the block + if ev.DerivedFrom != (eth.L1BlockRef{}) { + eq.emitter.Emit(PayloadProcessEvent{ + IsLastInSpan: ev.IsLastInSpan, + DerivedFrom: ev.DerivedFrom, + Envelope: ev.Envelope, + Ref: ev.Ref, + }) + } +} diff --git a/op-node/rollup/engine/build_start.go b/op-node/rollup/engine/build_start.go new file mode 100644 index 0000000000000..c1f9df5a98d6c --- /dev/null +++ b/op-node/rollup/engine/build_start.go @@ -0,0 +1,70 @@ +package engine + +import ( + "context" + "fmt" + "time" + + "github.com/ethereum-optimism/optimism/op-node/rollup" + "github.com/ethereum-optimism/optimism/op-node/rollup/derive" + "github.com/ethereum-optimism/optimism/op-service/eth" +) + +type BuildStartEvent struct { + Attributes *derive.AttributesWithParent +} + +func (ev BuildStartEvent) String() string { + return "build-start" +} + +func (eq *EngDeriver) onBuildStart(ev BuildStartEvent) { + ctx, cancel := context.WithTimeout(eq.ctx, buildStartTimeout) + defer cancel() + + if ev.Attributes.DerivedFrom != (eth.L1BlockRef{}) && + eq.ec.PendingSafeL2Head().Hash != ev.Attributes.Parent.Hash { + // Warn about small reorgs, happens when pending safe head is getting rolled back + eq.log.Warn("block-attributes derived from L1 do not build on pending safe head, likely reorg", + "pending_safe", eq.ec.PendingSafeL2Head(), "attributes_parent", ev.Attributes.Parent) + } + + fcEvent := ForkchoiceUpdateEvent{ + UnsafeL2Head: ev.Attributes.Parent, + SafeL2Head: eq.ec.safeHead, + FinalizedL2Head: eq.ec.finalizedHead, + } + fc := eth.ForkchoiceState{ + HeadBlockHash: fcEvent.UnsafeL2Head.Hash, + SafeBlockHash: fcEvent.SafeL2Head.Hash, + FinalizedBlockHash: fcEvent.FinalizedL2Head.Hash, + } + buildStartTime := time.Now() + id, errTyp, err := startPayload(ctx, eq.ec.engine, fc, ev.Attributes.Attributes) + if err != nil { + switch errTyp { + case BlockInsertTemporaryErr: + // RPC errors are recoverable, we can retry the buffered payload attributes later. + eq.emitter.Emit(rollup.EngineTemporaryErrorEvent{Err: fmt.Errorf("temporarily cannot insert new safe block: %w", err)}) + return + case BlockInsertPrestateErr: + eq.emitter.Emit(rollup.ResetEvent{Err: fmt.Errorf("need reset to resolve pre-state problem: %w", err)}) + return + case BlockInsertPayloadErr: + eq.emitter.Emit(BuildInvalidEvent{Attributes: ev.Attributes, Err: err}) + return + default: + eq.emitter.Emit(rollup.CriticalErrorEvent{Err: fmt.Errorf("unknown error type %d: %w", errTyp, err)}) + return + } + } + eq.emitter.Emit(fcEvent) + + eq.emitter.Emit(BuildStartedEvent{ + Info: eth.PayloadInfo{ID: id, Timestamp: uint64(ev.Attributes.Attributes.Timestamp)}, + BuildStarted: buildStartTime, + IsLastInSpan: ev.Attributes.IsLastInSpan, + DerivedFrom: ev.Attributes.DerivedFrom, + Parent: ev.Attributes.Parent, + }) +} diff --git a/op-node/rollup/engine/build_started.go b/op-node/rollup/engine/build_started.go new file mode 100644 index 0000000000000..78b737d214c77 --- /dev/null +++ b/op-node/rollup/engine/build_started.go @@ -0,0 +1,36 @@ +package engine + +import ( + "time" + + "github.com/ethereum-optimism/optimism/op-service/eth" +) + +type BuildStartedEvent struct { + Info eth.PayloadInfo + + BuildStarted time.Time + + Parent eth.L2BlockRef + + // if payload should be promoted to safe (must also be pending safe, see DerivedFrom) + IsLastInSpan bool + // payload is promoted to pending-safe if non-zero + DerivedFrom eth.L1BlockRef +} + +func (ev BuildStartedEvent) String() string { + return "build-started" +} + +func (eq *EngDeriver) onBuildStarted(ev BuildStartedEvent) { + // If a (pending) safe block, immediately seal the block + if ev.DerivedFrom != (eth.L1BlockRef{}) { + eq.emitter.Emit(BuildSealEvent{ + Info: ev.Info, + BuildStarted: ev.BuildStarted, + IsLastInSpan: ev.IsLastInSpan, + DerivedFrom: ev.DerivedFrom, + }) + } +} diff --git a/op-node/rollup/engine/engine_controller.go b/op-node/rollup/engine/engine_controller.go index b963be4a59ee8..d8db9cad949c6 100644 --- a/op-node/rollup/engine/engine_controller.go +++ b/op-node/rollup/engine/engine_controller.go @@ -11,8 +11,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum-optimism/optimism/op-node/rollup" - "github.com/ethereum-optimism/optimism/op-node/rollup/async" - "github.com/ethereum-optimism/optimism/op-node/rollup/conductor" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-node/rollup/event" "github.com/ethereum-optimism/optimism/op-node/rollup/sync" @@ -70,12 +68,6 @@ type EngineController struct { // because engine may forgot backupUnsafeHead or backupUnsafeHead is not part // of the chain. needFCUCallForBackupUnsafeReorg bool - - // Building State - buildingOnto eth.L2BlockRef - buildingInfo eth.PayloadInfo - buildingSafe bool - safeAttrs *derive.AttributesWithParent } func NewEngineController(engine ExecEngine, log log.Logger, metrics derive.Metrics, @@ -120,10 +112,6 @@ func (e *EngineController) BackupUnsafeL2Head() eth.L2BlockRef { return e.backupUnsafeHead } -func (e *EngineController) BuildingPayload() (eth.L2BlockRef, eth.PayloadID, bool) { - return e.buildingOnto, e.buildingInfo.ID, e.buildingSafe -} - func (e *EngineController) IsEngineSyncing() bool { return e.syncStatus == syncStatusWillStartEL || e.syncStatus == syncStatusStartedEL || e.syncStatus == syncStatusFinishedELButNotFinalized } @@ -209,121 +197,6 @@ func (e *EngineController) logSyncProgressMaybe() func() { } } -// Engine Methods - -func (e *EngineController) StartPayload(ctx context.Context, parent eth.L2BlockRef, attrs *derive.AttributesWithParent, updateSafe bool) (errType BlockInsertionErrType, err error) { - if e.IsEngineSyncing() { - return BlockInsertTemporaryErr, fmt.Errorf("engine is in progess of p2p sync") - } - if e.buildingInfo != (eth.PayloadInfo{}) { - e.log.Warn("did not finish previous block building, starting new building now", "prev_onto", e.buildingOnto, "prev_payload_id", e.buildingInfo.ID, "new_onto", parent) - // TODO(8841): maybe worth it to force-cancel the old payload ID here. - } - fc := eth.ForkchoiceState{ - HeadBlockHash: parent.Hash, - SafeBlockHash: e.safeHead.Hash, - FinalizedBlockHash: e.finalizedHead.Hash, - } - - id, errTyp, err := startPayload(ctx, e.engine, fc, attrs.Attributes) - if err != nil { - return errTyp, err - } - e.emitter.Emit(ForkchoiceUpdateEvent{ - UnsafeL2Head: parent, - SafeL2Head: e.safeHead, - FinalizedL2Head: e.finalizedHead, - }) - - e.buildingInfo = eth.PayloadInfo{ID: id, Timestamp: uint64(attrs.Attributes.Timestamp)} - e.buildingSafe = updateSafe - e.buildingOnto = parent - if updateSafe { - e.safeAttrs = attrs - } - - return BlockInsertOK, nil -} - -func (e *EngineController) ConfirmPayload(ctx context.Context, agossip async.AsyncGossiper, sequencerConductor conductor.SequencerConductor) (out *eth.ExecutionPayloadEnvelope, errTyp BlockInsertionErrType, err error) { - // don't create a BlockInsertPrestateErr if we have a cached gossip payload - if e.buildingInfo == (eth.PayloadInfo{}) && agossip.Get() == nil { - return nil, BlockInsertPrestateErr, fmt.Errorf("cannot complete payload building: not currently building a payload") - } - if p := agossip.Get(); p != nil && e.buildingOnto == (eth.L2BlockRef{}) { - e.log.Warn("Found reusable payload from async gossiper, and no block was being built. Reusing payload.", - "hash", p.ExecutionPayload.BlockHash, - "number", uint64(p.ExecutionPayload.BlockNumber), - "parent", p.ExecutionPayload.ParentHash) - } else if e.buildingOnto.Hash != e.unsafeHead.Hash { // E.g. when safe-attributes consolidation fails, it will drop the existing work. - e.log.Warn("engine is building block that reorgs previous unsafe head", "onto", e.buildingOnto, "unsafe", e.unsafeHead) - } - fc := eth.ForkchoiceState{ - HeadBlockHash: common.Hash{}, // gets overridden - SafeBlockHash: e.safeHead.Hash, - FinalizedBlockHash: e.finalizedHead.Hash, - } - // Update the safe head if the payload is built with the last attributes in the batch. - updateSafe := e.buildingSafe && e.safeAttrs != nil && e.safeAttrs.IsLastInSpan - envelope, errTyp, err := confirmPayload(ctx, e.log, e.engine, fc, e.buildingInfo, updateSafe, agossip, sequencerConductor) - if err != nil { - return nil, errTyp, fmt.Errorf("failed to complete building on top of L2 chain %s, id: %s, error (%d): %w", e.buildingOnto, e.buildingInfo.ID, errTyp, err) - } - ref, err := derive.PayloadToBlockRef(e.rollupCfg, envelope.ExecutionPayload) - if err != nil { - return nil, BlockInsertPayloadErr, derive.NewResetError(fmt.Errorf("failed to decode L2 block ref from payload: %w", err)) - } - // Backup unsafeHead when new block is not built on original unsafe head. - if e.unsafeHead.Number >= ref.Number { - e.SetBackupUnsafeL2Head(e.unsafeHead, false) - } - e.unsafeHead = ref - - e.metrics.RecordL2Ref("l2_unsafe", ref) - if e.buildingSafe { - e.metrics.RecordL2Ref("l2_pending_safe", ref) - e.pendingSafeHead = ref - if updateSafe { - e.safeHead = ref - e.metrics.RecordL2Ref("l2_safe", ref) - // Remove backupUnsafeHead because this backup will be never used after consolidation. - e.SetBackupUnsafeL2Head(eth.L2BlockRef{}, false) - } - } - e.emitter.Emit(ForkchoiceUpdateEvent{ - UnsafeL2Head: e.unsafeHead, - SafeL2Head: e.safeHead, - FinalizedL2Head: e.finalizedHead, - }) - - e.resetBuildingState() - return envelope, BlockInsertOK, nil -} - -func (e *EngineController) CancelPayload(ctx context.Context, force bool) error { - if e.buildingInfo == (eth.PayloadInfo{}) { // only cancel if there is something to cancel. - return nil - } - // the building job gets wrapped up as soon as the payload is retrieved, there's no explicit cancel in the Engine API - e.log.Error("cancelling old block sealing job", "payload", e.buildingInfo.ID) - _, err := e.engine.GetPayload(ctx, e.buildingInfo) - if err != nil { - e.log.Error("failed to cancel block building job", "payload", e.buildingInfo.ID, "err", err) - if !force { - return err - } - } - e.resetBuildingState() - return nil -} - -func (e *EngineController) resetBuildingState() { - e.buildingInfo = eth.PayloadInfo{} - e.buildingOnto = eth.L2BlockRef{} - e.buildingSafe = false - e.safeAttrs = nil -} - // Misc Setters only used by the engine queue // checkNewPayloadStatus checks returned status of engine_newPayloadV1 request for next unsafe payload. @@ -389,6 +262,10 @@ func (e *EngineController) TryUpdateEngine(ctx context.Context) error { FinalizedL2Head: e.finalizedHead, }) } + if e.unsafeHead == e.safeHead && e.safeHead == e.pendingSafeHead { + // Remove backupUnsafeHead because this backup will be never used after consolidation. + e.SetBackupUnsafeL2Head(eth.L2BlockRef{}, false) + } e.needFCUCall = false return nil } @@ -416,7 +293,7 @@ func (e *EngineController) InsertUnsafePayload(ctx context.Context, envelope *et return derive.NewTemporaryError(fmt.Errorf("failed to update insert payload: %w", err)) } if status.Status == eth.ExecutionInvalid { - e.emitter.Emit(InvalidPayloadEvent{Envelope: envelope}) + e.emitter.Emit(PayloadInvalidEvent{Envelope: envelope, Err: eth.NewPayloadErr(envelope.ExecutionPayload, status)}) } if !e.checkNewPayloadStatus(status.Status) { payload := envelope.ExecutionPayload @@ -550,8 +427,3 @@ func (e *EngineController) TryBackupUnsafeReorg(ctx context.Context) (bool, erro return true, derive.NewTemporaryError(fmt.Errorf("cannot restore unsafe chain using backupUnsafe: err: %w", eth.ForkchoiceUpdateErr(fcRes.PayloadStatus))) } - -// ResetBuildingState implements LocalEngineControl. -func (e *EngineController) ResetBuildingState() { - e.resetBuildingState() -} diff --git a/op-node/rollup/engine/engine_reset.go b/op-node/rollup/engine/engine_reset.go index f34ae4d249bca..a3e901eb26194 100644 --- a/op-node/rollup/engine/engine_reset.go +++ b/op-node/rollup/engine/engine_reset.go @@ -32,7 +32,7 @@ type EngineResetDeriver struct { } func NewEngineResetDeriver(ctx context.Context, log log.Logger, cfg *rollup.Config, - l1 sync.L1Chain, l2 sync.L2Chain, syncCfg *sync.Config, emitter event.Emitter) *EngineResetDeriver { + l1 sync.L1Chain, l2 sync.L2Chain, syncCfg *sync.Config) *EngineResetDeriver { return &EngineResetDeriver{ ctx: ctx, log: log, @@ -40,22 +40,28 @@ func NewEngineResetDeriver(ctx context.Context, log log.Logger, cfg *rollup.Conf l1: l1, l2: l2, syncCfg: syncCfg, - emitter: emitter, } } -func (d *EngineResetDeriver) OnEvent(ev event.Event) { +func (d *EngineResetDeriver) AttachEmitter(em event.Emitter) { + d.emitter = em +} + +func (d *EngineResetDeriver) OnEvent(ev event.Event) bool { switch ev.(type) { case ResetEngineRequestEvent: result, err := sync.FindL2Heads(d.ctx, d.cfg, d.l1, d.l2, d.log, d.syncCfg) if err != nil { d.emitter.Emit(rollup.ResetEvent{Err: fmt.Errorf("failed to find the L2 Heads to start from: %w", err)}) - return + return true } d.emitter.Emit(ForceEngineResetEvent{ Unsafe: result.Unsafe, Safe: result.Safe, Finalized: result.Finalized, }) + default: + return false } + return true } diff --git a/op-node/rollup/engine/engine_update.go b/op-node/rollup/engine/engine_update.go index 68d1f74bf7f5f..8f100709bcc16 100644 --- a/op-node/rollup/engine/engine_update.go +++ b/op-node/rollup/engine/engine_update.go @@ -5,12 +5,8 @@ import ( "errors" "fmt" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/log" - - "github.com/ethereum-optimism/optimism/op-node/rollup/async" - "github.com/ethereum-optimism/optimism/op-node/rollup/conductor" "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum/go-ethereum/core/types" ) // isDepositTx checks an opaqueTx to determine if it is a Deposit Transaction @@ -68,6 +64,8 @@ func sanityCheckPayload(payload *eth.ExecutionPayload) error { return nil } +var ErrEngineSyncing = errors.New("engine is syncing") + type BlockInsertionErrType uint const ( @@ -94,7 +92,11 @@ func startPayload(ctx context.Context, eng ExecEngine, fc eth.ForkchoiceState, a case eth.InvalidPayloadAttributes: return eth.PayloadID{}, BlockInsertPayloadErr, fmt.Errorf("payload attributes are not valid, cannot build block: %w", inputErr.Unwrap()) default: - return eth.PayloadID{}, BlockInsertPrestateErr, fmt.Errorf("unexpected error code in forkchoice-updated response: %w", err) + if inputErr.Code.IsEngineError() { + return eth.PayloadID{}, BlockInsertPrestateErr, fmt.Errorf("unexpected engine error code in forkchoice-updated response: %w", err) + } else { + return eth.PayloadID{}, BlockInsertTemporaryErr, fmt.Errorf("unexpected generic error code in forkchoice-updated response: %w", err) + } } } else { return eth.PayloadID{}, BlockInsertTemporaryErr, fmt.Errorf("failed to create new block via forkchoice: %w", err) @@ -111,92 +113,9 @@ func startPayload(ctx context.Context, eng ExecEngine, fc eth.ForkchoiceState, a return eth.PayloadID{}, BlockInsertTemporaryErr, errors.New("nil id in forkchoice result when expecting a valid ID") } return *id, BlockInsertOK, nil + case eth.ExecutionSyncing: + return eth.PayloadID{}, BlockInsertTemporaryErr, ErrEngineSyncing default: return eth.PayloadID{}, BlockInsertTemporaryErr, eth.ForkchoiceUpdateErr(fcRes.PayloadStatus) } } - -// confirmPayload ends an execution payload building process in the provided Engine, and persists the payload as the canonical head. -// If updateSafe is true, then the payload will also be recognized as safe-head at the same time. -// The severity of the error is distinguished to determine whether the payload was valid and can become canonical. -func confirmPayload( - ctx context.Context, - log log.Logger, - eng ExecEngine, - fc eth.ForkchoiceState, - payloadInfo eth.PayloadInfo, - updateSafe bool, - agossip async.AsyncGossiper, - sequencerConductor conductor.SequencerConductor, -) (out *eth.ExecutionPayloadEnvelope, errTyp BlockInsertionErrType, err error) { - var envelope *eth.ExecutionPayloadEnvelope - // if the payload is available from the async gossiper, it means it was not yet imported, so we reuse it - if cached := agossip.Get(); cached != nil { - envelope = cached - // log a limited amount of information about the reused payload, more detailed logging happens later down - log.Debug("found uninserted payload from async gossiper, reusing it and bypassing engine", - "hash", envelope.ExecutionPayload.BlockHash, - "number", uint64(envelope.ExecutionPayload.BlockNumber), - "parent", envelope.ExecutionPayload.ParentHash, - "txs", len(envelope.ExecutionPayload.Transactions)) - } else { - envelope, err = eng.GetPayload(ctx, payloadInfo) - } - if err != nil { - // even if it is an input-error (unknown payload ID), it is temporary, since we will re-attempt the full payload building, not just the retrieval of the payload. - return nil, BlockInsertTemporaryErr, fmt.Errorf("failed to get execution payload: %w", err) - } - payload := envelope.ExecutionPayload - if err := sanityCheckPayload(payload); err != nil { - return nil, BlockInsertPayloadErr, err - } - if err := sequencerConductor.CommitUnsafePayload(ctx, envelope); err != nil { - return nil, BlockInsertTemporaryErr, fmt.Errorf("failed to commit unsafe payload to conductor: %w", err) - } - // begin gossiping as soon as possible - // agossip.Clear() will be called later if an non-temporary error is found, or if the payload is successfully inserted - agossip.Gossip(envelope) - - status, err := eng.NewPayload(ctx, payload, envelope.ParentBeaconBlockRoot) - if err != nil { - return nil, BlockInsertTemporaryErr, fmt.Errorf("failed to insert execution payload: %w", err) - } - if status.Status == eth.ExecutionInvalid || status.Status == eth.ExecutionInvalidBlockHash { - agossip.Clear() - return nil, BlockInsertPayloadErr, eth.NewPayloadErr(payload, status) - } - if status.Status != eth.ExecutionValid { - return nil, BlockInsertTemporaryErr, eth.NewPayloadErr(payload, status) - } - - fc.HeadBlockHash = payload.BlockHash - if updateSafe { - fc.SafeBlockHash = payload.BlockHash - } - fcRes, err := eng.ForkchoiceUpdate(ctx, &fc, nil) - if err != nil { - var inputErr eth.InputError - if errors.As(err, &inputErr) { - switch inputErr.Code { - case eth.InvalidForkchoiceState: - // if we succeed to update the forkchoice pre-payload, but fail post-payload, then it is a payload error - agossip.Clear() - return nil, BlockInsertPayloadErr, fmt.Errorf("post-block-creation forkchoice update was inconsistent with engine, need reset to resolve: %w", inputErr.Unwrap()) - default: - agossip.Clear() - return nil, BlockInsertPrestateErr, fmt.Errorf("unexpected error code in forkchoice-updated response: %w", err) - } - } else { - return nil, BlockInsertTemporaryErr, fmt.Errorf("failed to make the new L2 block canonical via forkchoice: %w", err) - } - } - agossip.Clear() - if fcRes.PayloadStatus.Status != eth.ExecutionValid { - return nil, BlockInsertPayloadErr, eth.ForkchoiceUpdateErr(fcRes.PayloadStatus) - } - log.Info("inserted block", "hash", payload.BlockHash, "number", uint64(payload.BlockNumber), - "state_root", payload.StateRoot, "timestamp", uint64(payload.Timestamp), "parent", payload.ParentHash, - "prev_randao", payload.PrevRandao, "fee_recipient", payload.FeeRecipient, - "txs", len(payload.Transactions), "update_safe", updateSafe) - return envelope, BlockInsertOK, nil -} diff --git a/op-node/rollup/engine/events.go b/op-node/rollup/engine/events.go index 12e1ff03ab835..325118825fcee 100644 --- a/op-node/rollup/engine/events.go +++ b/op-node/rollup/engine/events.go @@ -6,31 +6,19 @@ import ( "fmt" "time" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum-optimism/optimism/op-node/rollup" - "github.com/ethereum-optimism/optimism/op-node/rollup/async" - "github.com/ethereum-optimism/optimism/op-node/rollup/conductor" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-node/rollup/event" "github.com/ethereum-optimism/optimism/op-service/eth" ) -type InvalidPayloadEvent struct { - Envelope *eth.ExecutionPayloadEnvelope -} - -func (ev InvalidPayloadEvent) String() string { - return "invalid-payload" -} +type Metrics interface { + CountSequencedTxs(count int) -type InvalidPayloadAttributesEvent struct { - Attributes *derive.AttributesWithParent -} - -func (ev InvalidPayloadAttributesEvent) String() string { - return "invalid-payload-attributes" + RecordSequencerBuildingDiffTime(duration time.Duration) + RecordSequencerSealingTime(duration time.Duration) } // ForkchoiceRequestEvent signals to the engine that it should emit an artificial @@ -82,6 +70,7 @@ func (ev SafeDerivedEvent) String() string { return "safe-derived" } +// ProcessAttributesEvent signals to immediately process the attributes. type ProcessAttributesEvent struct { Attributes *derive.AttributesWithParent } @@ -145,6 +134,8 @@ func (ev PromoteFinalizedEvent) String() string { } type EngDeriver struct { + metrics Metrics + log log.Logger cfg *rollup.Config ec *EngineController @@ -155,17 +146,21 @@ type EngDeriver struct { var _ event.Deriver = (*EngDeriver)(nil) func NewEngDeriver(log log.Logger, ctx context.Context, cfg *rollup.Config, - ec *EngineController, emitter event.Emitter) *EngDeriver { + metrics Metrics, ec *EngineController) *EngDeriver { return &EngDeriver{ log: log, cfg: cfg, ec: ec, ctx: ctx, - emitter: emitter, + metrics: metrics, } } -func (d *EngDeriver) OnEvent(ev event.Event) { +func (d *EngDeriver) AttachEmitter(em event.Emitter) { + d.emitter = em +} + +func (d *EngDeriver) OnEvent(ev event.Event) bool { switch x := ev.(type) { case TryBackupUnsafeReorgEvent: // If we don't need to call FCU to restore unsafeHead using backupUnsafe, keep going b/c @@ -204,7 +199,7 @@ func (d *EngDeriver) OnEvent(ev event.Event) { ref, err := derive.PayloadToBlockRef(d.cfg, x.Envelope.ExecutionPayload) if err != nil { d.log.Error("failed to decode L2 block ref from payload", "err", err) - return + return true } if err := d.ec.InsertUnsafePayload(d.ctx, x.Envelope, ref); err != nil { d.log.Info("failed to insert payload", "ref", ref, @@ -239,8 +234,6 @@ func (d *EngDeriver) OnEvent(ev event.Event) { "safeHead", x.Safe, "unsafe", x.Unsafe, "safe_timestamp", x.Safe.Time, "unsafe_timestamp", x.Unsafe.Time) d.emitter.Emit(EngineResetConfirmedEvent(x)) - case ProcessAttributesEvent: - d.onForceNextSafeAttributes(x.Attributes) case PendingSafeRequestEvent: d.emitter.Emit(PendingSafeUpdateEvent{ PendingSafe: d.ec.PendingSafeL2Head(), @@ -251,96 +244,51 @@ func (d *EngDeriver) OnEvent(ev event.Event) { // Resets/overwrites happen through engine-resets, not through promotion. if x.Ref.Number > d.ec.PendingSafeL2Head().Number { d.ec.SetPendingSafeL2Head(x.Ref) + d.emitter.Emit(PendingSafeUpdateEvent{ + PendingSafe: d.ec.PendingSafeL2Head(), + Unsafe: d.ec.UnsafeL2Head(), + }) } if x.Safe && x.Ref.Number > d.ec.SafeL2Head().Number { d.ec.SetSafeHead(x.Ref) d.emitter.Emit(SafeDerivedEvent{Safe: x.Ref, DerivedFrom: x.DerivedFrom}) + // Try to apply the forkchoice changes + d.emitter.Emit(TryUpdateEngineEvent{}) } case PromoteFinalizedEvent: if x.Ref.Number < d.ec.Finalized().Number { d.log.Error("Cannot rewind finality,", "ref", x.Ref, "finalized", d.ec.Finalized()) - return + return true } if x.Ref.Number > d.ec.SafeL2Head().Number { d.log.Error("Block must be safe before it can be finalized", "ref", x.Ref, "safe", d.ec.SafeL2Head()) - return + return true } d.ec.SetFinalizedHead(x.Ref) // Try to apply the forkchoice changes d.emitter.Emit(TryUpdateEngineEvent{}) + case BuildStartEvent: + d.onBuildStart(x) + case BuildStartedEvent: + d.onBuildStarted(x) + case BuildSealedEvent: + d.onBuildSealed(x) + case BuildSealEvent: + d.onBuildSeal(x) + case BuildInvalidEvent: + d.onBuildInvalid(x) + case BuildCancelEvent: + d.onBuildCancel(x) + case PayloadProcessEvent: + d.onPayloadProcess(x) + case PayloadSuccessEvent: + d.onPayloadSuccess(x) + case PayloadInvalidEvent: + d.onPayloadInvalid(x) + default: + return false } -} - -// onForceNextSafeAttributes inserts the provided attributes, reorging away any conflicting unsafe chain. -func (eq *EngDeriver) onForceNextSafeAttributes(attributes *derive.AttributesWithParent) { - ctx, cancel := context.WithTimeout(eq.ctx, time.Second*10) - defer cancel() - - attrs := attributes.Attributes - errType, err := eq.ec.StartPayload(ctx, eq.ec.PendingSafeL2Head(), attributes, true) - var envelope *eth.ExecutionPayloadEnvelope - if err == nil { - envelope, errType, err = eq.ec.ConfirmPayload(ctx, async.NoOpGossiper{}, &conductor.NoOpConductor{}) - } - if err != nil { - switch errType { - case BlockInsertTemporaryErr: - // RPC errors are recoverable, we can retry the buffered payload attributes later. - eq.emitter.Emit(rollup.EngineTemporaryErrorEvent{Err: fmt.Errorf("temporarily cannot insert new safe block: %w", err)}) - return - case BlockInsertPrestateErr: - _ = eq.ec.CancelPayload(ctx, true) - eq.emitter.Emit(rollup.ResetEvent{Err: fmt.Errorf("need reset to resolve pre-state problem: %w", err)}) - return - case BlockInsertPayloadErr: - if !errors.Is(err, derive.ErrTemporary) { - eq.emitter.Emit(InvalidPayloadAttributesEvent{Attributes: attributes}) - } - _ = eq.ec.CancelPayload(ctx, true) - eq.log.Warn("could not process payload derived from L1 data, dropping attributes", "err", err) - // Count the number of deposits to see if the tx list is deposit only. - depositCount := 0 - for _, tx := range attrs.Transactions { - if len(tx) > 0 && tx[0] == types.DepositTxType { - depositCount += 1 - } - } - // Deposit transaction execution errors are suppressed in the execution engine, but if the - // block is somehow invalid, there is nothing we can do to recover & we should exit. - if len(attrs.Transactions) == depositCount { - eq.log.Error("deposit only block was invalid", "parent", attributes.Parent, "err", err) - eq.emitter.Emit(rollup.CriticalErrorEvent{Err: fmt.Errorf("failed to process block with only deposit transactions: %w", err)}) - return - } - // Revert the pending safe head to the safe head. - eq.ec.SetPendingSafeL2Head(eq.ec.SafeL2Head()) - // suppress the error b/c we want to retry with the next batch from the batch queue - // If there is no valid batch the node will eventually force a deposit only block. If - // the deposit only block fails, this will return the critical error above. - - // Try to restore to previous known unsafe chain. - eq.ec.SetBackupUnsafeL2Head(eq.ec.BackupUnsafeL2Head(), true) - - // drop the payload without inserting it into the engine - return - default: - eq.emitter.Emit(rollup.CriticalErrorEvent{Err: fmt.Errorf("unknown InsertHeadBlock error type %d: %w", errType, err)}) - } - } - ref, err := derive.PayloadToBlockRef(eq.cfg, envelope.ExecutionPayload) - if err != nil { - eq.emitter.Emit(rollup.ResetEvent{Err: fmt.Errorf("failed to decode L2 block ref from payload: %w", err)}) - return - } - eq.ec.SetPendingSafeL2Head(ref) - if attributes.IsLastInSpan { - eq.ec.SetSafeHead(ref) - eq.emitter.Emit(SafeDerivedEvent{Safe: ref, DerivedFrom: attributes.DerivedFrom}) - } - eq.emitter.Emit(PendingSafeUpdateEvent{ - PendingSafe: eq.ec.PendingSafeL2Head(), - Unsafe: eq.ec.UnsafeL2Head(), - }) + return true } type ResetEngineControl interface { @@ -349,7 +297,6 @@ type ResetEngineControl interface { SetFinalizedHead(eth.L2BlockRef) SetBackupUnsafeL2Head(block eth.L2BlockRef, triggerReorg bool) SetPendingSafeL2Head(eth.L2BlockRef) - ResetBuildingState() } // ForceEngineReset is not to be used. The op-program needs it for now, until event processing is adopted there. @@ -359,5 +306,4 @@ func ForceEngineReset(ec ResetEngineControl, x ForceEngineResetEvent) { ec.SetPendingSafeL2Head(x.Safe) ec.SetFinalizedHead(x.Finalized) ec.SetBackupUnsafeL2Head(eth.L2BlockRef{}, false) - ec.ResetBuildingState() } diff --git a/op-node/rollup/engine/iface.go b/op-node/rollup/engine/iface.go index 37c4278ac5a75..0989b125df795 100644 --- a/op-node/rollup/engine/iface.go +++ b/op-node/rollup/engine/iface.go @@ -1,10 +1,6 @@ package engine import ( - "context" - - "github.com/ethereum-optimism/optimism/op-node/rollup/async" - "github.com/ethereum-optimism/optimism/op-node/rollup/conductor" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-service/eth" ) @@ -21,24 +17,6 @@ type Engine interface { derive.L2Source } -// EngineControl enables other components to build blocks with the Engine, -// while keeping the forkchoice state and payload-id management internal to -// avoid state inconsistencies between different users of the EngineControl. -type EngineControl interface { - EngineState - - // StartPayload requests the engine to start building a block with the given attributes. - // If updateSafe, the resulting block will be marked as a safe block. - StartPayload(ctx context.Context, parent eth.L2BlockRef, attrs *derive.AttributesWithParent, updateSafe bool) (errType BlockInsertionErrType, err error) - // ConfirmPayload requests the engine to complete the current block. If no block is being built, or if it fails, an error is returned. - ConfirmPayload(ctx context.Context, agossip async.AsyncGossiper, sequencerConductor conductor.SequencerConductor) (out *eth.ExecutionPayloadEnvelope, errTyp BlockInsertionErrType, err error) - // CancelPayload requests the engine to stop building the current block without making it canonical. - // This is optional, as the engine expires building jobs that are left uncompleted, but can still save resources. - CancelPayload(ctx context.Context, force bool) error - // BuildingPayload indicates if a payload is being built, and onto which block it is being built, and whether or not it is a safe payload. - BuildingPayload() (onto eth.L2BlockRef, id eth.PayloadID, safe bool) -} - type LocalEngineState interface { EngineState @@ -48,19 +26,7 @@ type LocalEngineState interface { type LocalEngineControl interface { LocalEngineState - EngineControl ResetEngineControl } -type FinalizerHooks interface { - // OnDerivationL1End remembers the given L1 block, - // and finalizes any prior data with the latest finality signal based on block height. - OnDerivationL1End(ctx context.Context, derivedFrom eth.L1BlockRef) error - // PostProcessSafeL2 remembers the L2 block is derived from the given L1 block, for later finalization. - PostProcessSafeL2(l2Safe eth.L2BlockRef, derivedFrom eth.L1BlockRef) - // Reset clear recent state, to adapt to reorgs. - Reset() -} - -var _ EngineControl = (*EngineController)(nil) var _ LocalEngineControl = (*EngineController)(nil) diff --git a/op-node/rollup/engine/params.go b/op-node/rollup/engine/params.go new file mode 100644 index 0000000000000..979b304cdb485 --- /dev/null +++ b/op-node/rollup/engine/params.go @@ -0,0 +1,10 @@ +package engine + +import "time" + +const ( + buildSealTimeout = time.Second * 10 + buildStartTimeout = time.Second * 10 + buildCancelTimeout = time.Second * 10 + payloadProcessTimeout = time.Second * 10 +) diff --git a/op-node/rollup/engine/payload_invalid.go b/op-node/rollup/engine/payload_invalid.go new file mode 100644 index 0000000000000..464adabd30237 --- /dev/null +++ b/op-node/rollup/engine/payload_invalid.go @@ -0,0 +1,17 @@ +package engine + +import "github.com/ethereum-optimism/optimism/op-service/eth" + +type PayloadInvalidEvent struct { + Envelope *eth.ExecutionPayloadEnvelope + Err error +} + +func (ev PayloadInvalidEvent) String() string { + return "payload-invalid" +} + +func (eq *EngDeriver) onPayloadInvalid(ev PayloadInvalidEvent) { + eq.log.Warn("Payload was invalid", "block", ev.Envelope.ExecutionPayload.ID(), + "err", ev.Err, "timestamp", uint64(ev.Envelope.ExecutionPayload.Timestamp)) +} diff --git a/op-node/rollup/engine/payload_process.go b/op-node/rollup/engine/payload_process.go new file mode 100644 index 0000000000000..4102287f3d238 --- /dev/null +++ b/op-node/rollup/engine/payload_process.go @@ -0,0 +1,50 @@ +package engine + +import ( + "context" + "fmt" + + "github.com/ethereum-optimism/optimism/op-node/rollup" + "github.com/ethereum-optimism/optimism/op-service/eth" +) + +type PayloadProcessEvent struct { + // if payload should be promoted to safe (must also be pending safe, see DerivedFrom) + IsLastInSpan bool + // payload is promoted to pending-safe if non-zero + DerivedFrom eth.L1BlockRef + + Envelope *eth.ExecutionPayloadEnvelope + Ref eth.L2BlockRef +} + +func (ev PayloadProcessEvent) String() string { + return "payload-process" +} + +func (eq *EngDeriver) onPayloadProcess(ev PayloadProcessEvent) { + ctx, cancel := context.WithTimeout(eq.ctx, payloadProcessTimeout) + defer cancel() + + status, err := eq.ec.engine.NewPayload(ctx, + ev.Envelope.ExecutionPayload, ev.Envelope.ParentBeaconBlockRoot) + if err != nil { + eq.emitter.Emit(rollup.EngineTemporaryErrorEvent{ + Err: fmt.Errorf("failed to insert execution payload: %w", err)}) + return + } + switch status.Status { + case eth.ExecutionInvalid, eth.ExecutionInvalidBlockHash: + eq.emitter.Emit(PayloadInvalidEvent{ + Envelope: ev.Envelope, + Err: eth.NewPayloadErr(ev.Envelope.ExecutionPayload, status)}) + return + case eth.ExecutionValid: + eq.emitter.Emit(PayloadSuccessEvent(ev)) + return + default: + eq.emitter.Emit(rollup.EngineTemporaryErrorEvent{ + Err: eth.NewPayloadErr(ev.Envelope.ExecutionPayload, status)}) + return + } +} diff --git a/op-node/rollup/engine/payload_success.go b/op-node/rollup/engine/payload_success.go new file mode 100644 index 0000000000000..cdd2ee2d030b3 --- /dev/null +++ b/op-node/rollup/engine/payload_success.go @@ -0,0 +1,49 @@ +package engine + +import ( + "github.com/ethereum-optimism/optimism/op-service/eth" +) + +type PayloadSuccessEvent struct { + // if payload should be promoted to safe (must also be pending safe, see DerivedFrom) + IsLastInSpan bool + // payload is promoted to pending-safe if non-zero + DerivedFrom eth.L1BlockRef + + Envelope *eth.ExecutionPayloadEnvelope + Ref eth.L2BlockRef +} + +func (ev PayloadSuccessEvent) String() string { + return "payload-success" +} + +func (eq *EngDeriver) onPayloadSuccess(ev PayloadSuccessEvent) { + + // Backup unsafeHead when new block is not built on original unsafe head. + if eq.ec.unsafeHead.Number >= ev.Ref.Number { + eq.ec.SetBackupUnsafeL2Head(eq.ec.unsafeHead, false) + } + eq.ec.SetUnsafeHead(ev.Ref) + + // If derived from L1, then it can be considered (pending) safe + if ev.DerivedFrom != (eth.L1BlockRef{}) { + if ev.IsLastInSpan { + eq.ec.SetSafeHead(ev.Ref) + eq.emitter.Emit(SafeDerivedEvent{Safe: ev.Ref, DerivedFrom: ev.DerivedFrom}) + } + eq.ec.SetPendingSafeL2Head(ev.Ref) + eq.emitter.Emit(PendingSafeUpdateEvent{ + PendingSafe: eq.ec.PendingSafeL2Head(), + Unsafe: eq.ec.UnsafeL2Head(), + }) + } + + payload := ev.Envelope.ExecutionPayload + eq.log.Info("Inserted block", "hash", payload.BlockHash, "number", uint64(payload.BlockNumber), + "state_root", payload.StateRoot, "timestamp", uint64(payload.Timestamp), "parent", payload.ParentHash, + "prev_randao", payload.PrevRandao, "fee_recipient", payload.FeeRecipient, + "txs", len(payload.Transactions), "last_in_span", ev.IsLastInSpan, "derived_from", ev.DerivedFrom) + + eq.emitter.Emit(TryUpdateEngineEvent{}) +} diff --git a/op-node/rollup/event/events.go b/op-node/rollup/event/events.go index 35e30d0d4d075..ac550e203e551 100644 --- a/op-node/rollup/event/events.go +++ b/op-node/rollup/event/events.go @@ -10,7 +10,7 @@ type Event interface { } type Deriver interface { - OnEvent(ev Event) + OnEvent(ev Event) bool } type Emitter interface { @@ -41,10 +41,12 @@ func (fn EmitterFunc) Emit(ev Event) { // Technically this is a DeMux: single input to multi output. type DeriverMux []Deriver -func (s *DeriverMux) OnEvent(ev Event) { +func (s *DeriverMux) OnEvent(ev Event) bool { + out := false for _, d := range *s { - d.OnEvent(ev) + out = d.OnEvent(ev) || out } + return out } var _ Deriver = (*DeriverMux)(nil) @@ -64,10 +66,10 @@ func (d NoopDeriver) OnEvent(ev Event) {} // DeriverFunc implements the Deriver interface as a function, // similar to how the std-lib http HandlerFunc implements a Handler. // This can be used for small in-place derivers, test helpers, etc. -type DeriverFunc func(ev Event) +type DeriverFunc func(ev Event) bool -func (fn DeriverFunc) OnEvent(ev Event) { - fn(ev) +func (fn DeriverFunc) OnEvent(ev Event) bool { + return fn(ev) } type NoopEmitter struct{} diff --git a/op-node/rollup/event/events_test.go b/op-node/rollup/event/events_test.go index e52185601a564..91ee22304b9e0 100644 --- a/op-node/rollup/event/events_test.go +++ b/op-node/rollup/event/events_test.go @@ -15,14 +15,17 @@ func (ev TestEvent) String() string { func TestDeriverMux_OnEvent(t *testing.T) { result := "" - a := DeriverFunc(func(ev Event) { + a := DeriverFunc(func(ev Event) bool { result += fmt.Sprintf("A:%s\n", ev) + return true }) - b := DeriverFunc(func(ev Event) { + b := DeriverFunc(func(ev Event) bool { result += fmt.Sprintf("B:%s\n", ev) + return true }) - c := DeriverFunc(func(ev Event) { + c := DeriverFunc(func(ev Event) bool { result += fmt.Sprintf("C:%s\n", ev) + return true }) x := DeriverMux{} diff --git a/op-node/rollup/event/executor.go b/op-node/rollup/event/executor.go new file mode 100644 index 0000000000000..7f686a5414a4e --- /dev/null +++ b/op-node/rollup/event/executor.go @@ -0,0 +1,19 @@ +package event + +type Executable interface { + RunEvent(ev AnnotatedEvent) +} + +// ExecutableFunc implements the Executable interface as a function, +// similar to how the std-lib http HandlerFunc implements a Handler. +// This can be used for small in-place executables, test helpers, etc. +type ExecutableFunc func(ev AnnotatedEvent) + +func (fn ExecutableFunc) RunEvent(ev AnnotatedEvent) { + fn(ev) +} + +type Executor interface { + Add(d Executable, opts *ExecutorOpts) (leaveExecutor func()) + Enqueue(ev AnnotatedEvent) error +} diff --git a/op-node/rollup/event/executor_global.go b/op-node/rollup/event/executor_global.go new file mode 100644 index 0000000000000..07fcc01e8dd04 --- /dev/null +++ b/op-node/rollup/event/executor_global.go @@ -0,0 +1,163 @@ +package event + +import ( + "context" + "fmt" + "io" + "slices" + "sync" + "sync/atomic" +) + +// Don't queue up an endless number of events. +// At some point it's better to drop events and warn something is exploding the number of events. +const sanityEventLimit = 1000 + +type GlobalSyncExec struct { + eventsLock sync.Mutex + events []AnnotatedEvent + + handles []*globalHandle + handlesLock sync.RWMutex + + ctx context.Context +} + +var _ Executor = (*GlobalSyncExec)(nil) + +func NewGlobalSynchronous(ctx context.Context) *GlobalSyncExec { + return &GlobalSyncExec{ctx: ctx} +} + +func (gs *GlobalSyncExec) Add(d Executable, _ *ExecutorOpts) (leaveExecutor func()) { + gs.handlesLock.Lock() + defer gs.handlesLock.Unlock() + h := &globalHandle{d: d} + h.g.Store(gs) + gs.handles = append(gs.handles, h) + return h.leave +} + +func (gs *GlobalSyncExec) remove(h *globalHandle) { + gs.handlesLock.Lock() + defer gs.handlesLock.Unlock() + // Linear search to delete is fine, + // since we delete much less frequently than we process events with these. + for i, v := range gs.handles { + if v == h { + gs.handles = slices.Delete(gs.handles, i, i+1) + return + } + } +} + +func (gs *GlobalSyncExec) Enqueue(ev AnnotatedEvent) error { + gs.eventsLock.Lock() + defer gs.eventsLock.Unlock() + // sanity limit, never queue too many events + if len(gs.events) >= sanityEventLimit { + return fmt.Errorf("something is very wrong, queued up too many events! Dropping event %q", ev) + } + gs.events = append(gs.events, ev) + return nil +} + +func (gs *GlobalSyncExec) pop() AnnotatedEvent { + gs.eventsLock.Lock() + defer gs.eventsLock.Unlock() + + if len(gs.events) == 0 { + return AnnotatedEvent{} + } + + first := gs.events[0] + gs.events = gs.events[1:] + return first +} + +func (gs *GlobalSyncExec) processEvent(ev AnnotatedEvent) { + gs.handlesLock.RLock() // read lock, to allow Drain() to be called during event processing. + defer gs.handlesLock.RUnlock() + for _, h := range gs.handles { + h.onEvent(ev) + } +} + +func (gs *GlobalSyncExec) Drain() error { + for { + if gs.ctx.Err() != nil { + return gs.ctx.Err() + } + ev := gs.pop() + if ev.Event == nil { + return nil + } + // Note: event execution may call Drain(), that is allowed. + gs.processEvent(ev) + } +} + +func (gs *GlobalSyncExec) DrainUntil(fn func(ev Event) bool, excl bool) error { + // In order of operation: + // stopExcl: stop draining, and leave the event. + // no stopExcl, and no event: EOF, exhausted events before condition hit. + // no stopExcl, and event: process event. + // stopIncl: stop draining, after having processed the event first. + iter := func() (ev AnnotatedEvent, stopIncl bool, stopExcl bool) { + gs.eventsLock.Lock() + defer gs.eventsLock.Unlock() + + if len(gs.events) == 0 { + return AnnotatedEvent{}, false, false + } + + ev = gs.events[0] + stop := fn(ev.Event) + if excl && stop { + ev = AnnotatedEvent{} + stopExcl = true + } else { + gs.events = gs.events[1:] + } + if stop { + stopIncl = true + } + return + } + + for { + if gs.ctx.Err() != nil { + return gs.ctx.Err() + } + // includes popping of the event, so we can handle Drain() calls by onEvent() execution + ev, stopIncl, stopExcl := iter() + if stopExcl { + return nil + } + if ev.Event == nil { + return io.EOF + } + gs.processEvent(ev) + if stopIncl { + return nil + } + } +} + +type globalHandle struct { + g atomic.Pointer[GlobalSyncExec] + d Executable +} + +func (gh *globalHandle) onEvent(ev AnnotatedEvent) { + if gh.g.Load() == nil { // don't process more events while we are being removed + return + } + gh.d.RunEvent(ev) +} + +func (gh *globalHandle) leave() { + if old := gh.g.Swap(nil); old != nil { + old.remove(gh) + } +} diff --git a/op-node/rollup/event/executor_global_test.go b/op-node/rollup/event/executor_global_test.go new file mode 100644 index 0000000000000..d3b41ae054068 --- /dev/null +++ b/op-node/rollup/event/executor_global_test.go @@ -0,0 +1,158 @@ +package event + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/ethereum/go-ethereum/log" + + "github.com/ethereum-optimism/optimism/op-service/testlog" +) + +func TestGlobalExecutor(t *testing.T) { + count := 0 + ex := ExecutableFunc(func(ev AnnotatedEvent) { + count += 1 + }) + exec := NewGlobalSynchronous(context.Background()) + leave := exec.Add(ex, nil) + require.NoError(t, exec.Drain(), "can drain, even if empty") + + require.NoError(t, exec.Enqueue(AnnotatedEvent{Event: TestEvent{}})) + require.Equal(t, 0, count, "no processing yet, queued event") + require.NoError(t, exec.Drain()) + require.Equal(t, 1, count, "processed event") + + require.NoError(t, exec.Enqueue(AnnotatedEvent{Event: TestEvent{}})) + require.NoError(t, exec.Enqueue(AnnotatedEvent{Event: TestEvent{}})) + require.Equal(t, 1, count, "no processing yet, queued events") + require.NoError(t, exec.Drain()) + require.Equal(t, 3, count, "processed events") + + leave() + require.NoError(t, exec.Enqueue(AnnotatedEvent{Event: TestEvent{}})) + require.NotEqual(t, exec.Drain(), "after deriver leaves the executor can still drain events") + require.Equal(t, 3, count, "didn't process event after trigger close") +} + +func TestQueueSanityLimit(t *testing.T) { + count := 0 + ex := ExecutableFunc(func(ev AnnotatedEvent) { + count += 1 + }) + exec := NewGlobalSynchronous(context.Background()) + leave := exec.Add(ex, nil) + defer leave() + // emit 1 too many events + for i := 0; i < sanityEventLimit; i++ { + require.NoError(t, exec.Enqueue(AnnotatedEvent{Event: TestEvent{}})) + } + require.ErrorContains(t, exec.Enqueue(AnnotatedEvent{Event: TestEvent{}}), "too many events") + require.NoError(t, exec.Drain()) + require.Equal(t, sanityEventLimit, count, "processed all non-dropped events") + + require.NoError(t, exec.Enqueue(AnnotatedEvent{Event: TestEvent{}})) + require.NoError(t, exec.Drain()) + require.Equal(t, sanityEventLimit+1, count, "back to normal after drain") +} + +type CyclicEvent struct { + Count int +} + +func (ev CyclicEvent) String() string { + return "cyclic-event" +} + +func TestSynchronousCyclic(t *testing.T) { + logger := testlog.Logger(t, log.LevelError) + var exec *GlobalSyncExec + result := false + ex := ExecutableFunc(func(ev AnnotatedEvent) { + logger.Info("received event", "event", ev) + switch x := ev.Event.(type) { + case CyclicEvent: + if x.Count < 10 { + require.NoError(t, exec.Enqueue(AnnotatedEvent{Event: CyclicEvent{Count: x.Count + 1}})) + } else { + result = true + } + } + }) + exec = NewGlobalSynchronous(context.Background()) + leave := exec.Add(ex, nil) + defer leave() + require.NoError(t, exec.Enqueue(AnnotatedEvent{Event: CyclicEvent{Count: 0}})) + require.NoError(t, exec.Drain()) + require.True(t, result, "expecting event processing to fully recurse") +} + +func TestDrainCancel(t *testing.T) { + count := 0 + ctx, cancel := context.WithCancel(context.Background()) + ex := ExecutableFunc(func(ev AnnotatedEvent) { + count += 1 + cancel() + }) + exec := NewGlobalSynchronous(ctx) + leave := exec.Add(ex, nil) + defer leave() + + require.NoError(t, exec.Enqueue(AnnotatedEvent{Event: TestEvent{}})) + require.NoError(t, exec.Enqueue(AnnotatedEvent{Event: TestEvent{}})) + drainErr := exec.Drain() + require.NotNil(t, ctx.Err()) + require.ErrorIs(t, ctx.Err(), drainErr) + require.Equal(t, 1, count, "drain must be canceled before next event is processed") +} + +func TestDrainUntilCancel(t *testing.T) { + count := 0 + ctx, cancel := context.WithCancel(context.Background()) + ex := ExecutableFunc(func(ev AnnotatedEvent) { + count += 1 + if _, ok := ev.Event.(FooEvent); ok { + cancel() + } + }) + exec := NewGlobalSynchronous(ctx) + leave := exec.Add(ex, nil) + defer leave() + + require.NoError(t, exec.Enqueue(AnnotatedEvent{Event: TestEvent{}})) + require.NoError(t, exec.Enqueue(AnnotatedEvent{Event: FooEvent{}})) + require.NoError(t, exec.Enqueue(AnnotatedEvent{Event: TestEvent{}})) + drainErr := exec.DrainUntil(Is[FooEvent], false) + require.NoError(t, drainErr, "drained right until context started to matter") + require.Equal(t, 2, count, "drain must be stopped at Foo (incl)") + drainErr = exec.DrainUntil(Is[TestEvent], false) + require.NotNil(t, ctx.Err()) + require.NotNil(t, drainErr) + require.ErrorIs(t, ctx.Err(), drainErr) + require.Equal(t, 2, count, "drain must be canceled, not processed next TestEvent") +} + +func TestDrainUntilExcl(t *testing.T) { + count := 0 + ex := ExecutableFunc(func(ev AnnotatedEvent) { + count += 1 + }) + exec := NewGlobalSynchronous(context.Background()) + leave := exec.Add(ex, nil) + defer leave() + + require.NoError(t, exec.Enqueue(AnnotatedEvent{Event: TestEvent{}})) + require.NoError(t, exec.Enqueue(AnnotatedEvent{Event: FooEvent{}})) + require.NoError(t, exec.Enqueue(AnnotatedEvent{Event: TestEvent{}})) + require.NoError(t, exec.Enqueue(AnnotatedEvent{Event: TestEvent{}})) + require.NoError(t, exec.DrainUntil(Is[FooEvent], true)) + require.Equal(t, 1, count, "Foo must not be processed yet") + require.NoError(t, exec.DrainUntil(Is[FooEvent], true)) + require.Equal(t, 1, count, "Foo still not processed, excl on first element") + require.NoError(t, exec.DrainUntil(Is[FooEvent], false)) + require.Equal(t, 2, count, "Foo is processed, remainder is not, stop is inclusive now") + require.NoError(t, exec.Drain()) + require.Equal(t, 4, count, "Done") +} diff --git a/op-node/rollup/event/metrics.go b/op-node/rollup/event/metrics.go index 3c41b9b6efe91..bf3dec4e0644e 100644 --- a/op-node/rollup/event/metrics.go +++ b/op-node/rollup/event/metrics.go @@ -1,15 +1,20 @@ package event +import "time" + type Metrics interface { - RecordEmittedEvent(name string) - RecordProcessedEvent(name string) + RecordEmittedEvent(eventName string, emitter string) + RecordProcessedEvent(eventName string, deriver string, duration time.Duration) + RecordEventsRateLimited() } type NoopMetrics struct { } -func (n NoopMetrics) RecordEmittedEvent(name string) {} +func (n NoopMetrics) RecordEmittedEvent(eventName string, emitter string) {} + +func (n NoopMetrics) RecordProcessedEvent(eventName string, deriver string, duration time.Duration) {} -func (n NoopMetrics) RecordProcessedEvent(name string) {} +func (n NoopMetrics) RecordEventsRateLimited() {} var _ Metrics = NoopMetrics{} diff --git a/op-node/rollup/event/options.go b/op-node/rollup/event/options.go new file mode 100644 index 0000000000000..eca5a132a800b --- /dev/null +++ b/op-node/rollup/event/options.go @@ -0,0 +1,47 @@ +package event + +import "golang.org/x/time/rate" + +type ExecutorOpts struct { + Capacity int // If there is a local buffer capacity +} + +type EmitterOpts struct { + Limiting bool + Rate rate.Limit + Burst int + OnLimited func() +} + +// RegisterOpts represents the set of parameters to configure a +// new deriver/emitter with that is registered with an event System. +// These options may be reused for multiple registrations. +type RegisterOpts struct { + Executor ExecutorOpts + Emitter EmitterOpts +} + +// 200 events may be buffered per deriver before back-pressure has to kick in +const eventsBuffer = 200 + +// 10,000 events per second is plenty. +// If we are going through more events, the driver needs to breathe, and warn the user of a potential issue. +const eventsLimit = rate.Limit(10_000) + +// 500 events of burst: the maximum amount of events to eat up +// past the rate limit before the rate limit becomes applicable. +const eventsBurst = 500 + +func DefaultRegisterOpts() *RegisterOpts { + return &RegisterOpts{ + Executor: ExecutorOpts{ + Capacity: eventsBuffer, + }, + Emitter: EmitterOpts{ + Limiting: true, + Rate: eventsLimit, + Burst: eventsBurst, + OnLimited: nil, + }, + } +} diff --git a/op-node/rollup/event/queue.go b/op-node/rollup/event/queue.go deleted file mode 100644 index cee3f1e9985d5..0000000000000 --- a/op-node/rollup/event/queue.go +++ /dev/null @@ -1,115 +0,0 @@ -package event - -import ( - "context" - "io" - "sync" - - "github.com/ethereum/go-ethereum/log" -) - -// Don't queue up an endless number of events. -// At some point it's better to drop events and warn something is exploding the number of events. -const sanityEventLimit = 1000 - -// Queue is a event.Emitter that a event.Deriver can emit events to. -// The events will be queued up, and can then be executed synchronously by calling the Drain function, -// which will apply all events to the root Deriver. -// New events may be queued up while events are being processed by the root rollup.Deriver. -type Queue struct { - // The lock is no-op in FP execution, if running in synchronous FP-VM. - // This lock ensures that all emitted events are merged together correctly, - // if this util is used in a concurrent context. - evLock sync.Mutex - - events []Event - - log log.Logger - - ctx context.Context - - root Deriver - - metrics Metrics -} - -var _ EmitterDrainer = (*Queue)(nil) - -func NewQueue(log log.Logger, ctx context.Context, root Deriver, metrics Metrics) *Queue { - return &Queue{ - log: log, - ctx: ctx, - root: root, - metrics: metrics, - } -} - -func (s *Queue) Emit(event Event) { - s.evLock.Lock() - defer s.evLock.Unlock() - - s.log.Debug("Emitting event", "event", event) - s.metrics.RecordEmittedEvent(event.String()) - - if s.ctx.Err() != nil { - s.log.Warn("Ignoring emitted event during shutdown", "event", event) - return - } - - // sanity limit, never queue too many events - if len(s.events) >= sanityEventLimit { - s.log.Error("Something is very wrong, queued up too many events! Dropping event", "ev", event) - return - } - s.events = append(s.events, event) -} - -func (s *Queue) Drain() error { - for { - if s.ctx.Err() != nil { - return s.ctx.Err() - } - if len(s.events) == 0 { - return nil - } - - s.evLock.Lock() - first := s.events[0] - s.events = s.events[1:] - s.evLock.Unlock() - - s.log.Debug("Processing event", "event", first) - s.root.OnEvent(first) - s.metrics.RecordProcessedEvent(first.String()) - } -} - -func (s *Queue) DrainUntil(fn func(ev Event) bool, excl bool) error { - for { - if s.ctx.Err() != nil { - return s.ctx.Err() - } - if len(s.events) == 0 { - return io.EOF - } - - s.evLock.Lock() - first := s.events[0] - stop := fn(first) - if excl && stop { - s.evLock.Unlock() - return nil - } - s.events = s.events[1:] - s.evLock.Unlock() - - s.log.Debug("Processing event", "event", first) - s.root.OnEvent(first) - s.metrics.RecordProcessedEvent(first.String()) - if stop { - return nil - } - } -} - -var _ Emitter = (*Queue)(nil) diff --git a/op-node/rollup/event/queue_test.go b/op-node/rollup/event/queue_test.go deleted file mode 100644 index 696ce4e0babe0..0000000000000 --- a/op-node/rollup/event/queue_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package event - -import ( - "context" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/ethereum/go-ethereum/log" - - "github.com/ethereum-optimism/optimism/op-service/testlog" -) - -func TestQueue(t *testing.T) { - logger := testlog.Logger(t, log.LevelError) - ctx, cancel := context.WithCancel(context.Background()) - count := 0 - deriver := DeriverFunc(func(ev Event) { - count += 1 - }) - syncEv := NewQueue(logger, ctx, deriver, NoopMetrics{}) - require.NoError(t, syncEv.Drain(), "can drain, even if empty") - - syncEv.Emit(TestEvent{}) - require.Equal(t, 0, count, "no processing yet, queued event") - require.NoError(t, syncEv.Drain()) - require.Equal(t, 1, count, "processed event") - - syncEv.Emit(TestEvent{}) - syncEv.Emit(TestEvent{}) - require.Equal(t, 1, count, "no processing yet, queued events") - require.NoError(t, syncEv.Drain()) - require.Equal(t, 3, count, "processed events") - - cancel() - syncEv.Emit(TestEvent{}) - require.Equal(t, ctx.Err(), syncEv.Drain(), "no draining after close") - require.Equal(t, 3, count, "didn't process event after trigger close") -} - -func TestQueueSanityLimit(t *testing.T) { - logger := testlog.Logger(t, log.LevelCrit) // expecting error log of hitting sanity limit - count := 0 - deriver := DeriverFunc(func(ev Event) { - count += 1 - }) - syncEv := NewQueue(logger, context.Background(), deriver, NoopMetrics{}) - // emit 1 too many events - for i := 0; i < sanityEventLimit+1; i++ { - syncEv.Emit(TestEvent{}) - } - require.NoError(t, syncEv.Drain()) - require.Equal(t, sanityEventLimit, count, "processed all non-dropped events") - - syncEv.Emit(TestEvent{}) - require.NoError(t, syncEv.Drain()) - require.Equal(t, sanityEventLimit+1, count, "back to normal after drain") -} - -type CyclicEvent struct { - Count int -} - -func (ev CyclicEvent) String() string { - return "cyclic-event" -} - -func TestSynchronousCyclic(t *testing.T) { - logger := testlog.Logger(t, log.LevelError) - var emitter Emitter - result := false - deriver := DeriverFunc(func(ev Event) { - logger.Info("received event", "event", ev) - switch x := ev.(type) { - case CyclicEvent: - if x.Count < 10 { - emitter.Emit(CyclicEvent{Count: x.Count + 1}) - } else { - result = true - } - } - }) - syncEv := NewQueue(logger, context.Background(), deriver, NoopMetrics{}) - emitter = syncEv - syncEv.Emit(CyclicEvent{Count: 0}) - require.NoError(t, syncEv.Drain()) - require.True(t, result, "expecting event processing to fully recurse") -} diff --git a/op-node/rollup/event/system.go b/op-node/rollup/event/system.go new file mode 100644 index 0000000000000..3b59b89651b3e --- /dev/null +++ b/op-node/rollup/event/system.go @@ -0,0 +1,251 @@ +package event + +import ( + "context" + "fmt" + "slices" + "sync" + "sync/atomic" + "time" + + "github.com/ethereum/go-ethereum/log" +) + +type System interface { + // Register registers a named event-emitter, optionally processing events itself: + // deriver may be nil, not all registrants have to process events. + // A non-nil deriver may implement AttachEmitter to automatically attach the Emitter to it, + // before the deriver itself becomes executable. + Register(name string, deriver Deriver, opts *RegisterOpts) Emitter + // Unregister removes a named emitter, + // also removing it from the set of events-receiving derivers (if registered with non-nil deriver). + Unregister(name string) (old Emitter) + // AddTracer registers a tracer to capture all event deriver/emitter work. It runs until RemoveTracer is called. + // Duplicate tracers are allowed. + AddTracer(t Tracer) + // RemoveTracer removes a tracer. This is a no-op if the tracer was not previously added. + // It will remove all added duplicates of the tracer. + RemoveTracer(t Tracer) + // Stop shuts down the System by un-registering all derivers/emitters. + Stop() +} + +type AttachEmitter interface { + AttachEmitter(em Emitter) +} + +type AnnotatedEvent struct { + Event Event + EmitContext uint64 // uniquely identifies the emission of the event, useful for debugging and creating diagrams +} + +// systemActor is a deriver and/or emitter, registered in System with a name. +// If deriving, the actor is added as Executable to the Executor of the System. +type systemActor struct { + name string + sys *Sys + + // To manage the execution peripherals, like rate-limiting, of this deriver + ctx context.Context + cancel context.CancelFunc + + deriv Deriver + leaveExecutor func() + + // 0 if event does not originate from Deriver-handling of another event + currentEvent uint64 +} + +// Emit is called by the end-user +func (r *systemActor) Emit(ev Event) { + if r.ctx.Err() != nil { + return + } + r.sys.emit(r.name, r.currentEvent, ev) +} + +// RunEvent is called by the events executor. +// While different things may execute in parallel, only one event is executed per entry at a time. +func (r *systemActor) RunEvent(ev AnnotatedEvent) { + if r.deriv == nil { + return + } + if r.ctx.Err() != nil { + return + } + + prev := r.currentEvent + start := time.Now() + r.currentEvent = r.sys.recordDerivStart(r.name, ev, start) + effect := r.deriv.OnEvent(ev.Event) + elapsed := time.Since(start) + r.sys.recordDerivEnd(r.name, ev, r.currentEvent, start, elapsed, effect) + r.currentEvent = prev +} + +// Sys is the canonical implementation of System. +type Sys struct { + regs map[string]*systemActor + regsLock sync.Mutex + + log log.Logger + + executor Executor + + // used to generate a unique id for each event deriver processing call. + derivContext atomic.Uint64 + // used to generate a unique id for each event-emission. + emitContext atomic.Uint64 + + tracers []Tracer + tracersLock sync.RWMutex +} + +func NewSystem(log log.Logger, ex Executor) *Sys { + return &Sys{ + regs: make(map[string]*systemActor), + executor: ex, + log: log, + } +} + +func (s *Sys) Register(name string, deriver Deriver, opts *RegisterOpts) Emitter { + s.regsLock.Lock() + defer s.regsLock.Unlock() + + if _, ok := s.regs[name]; ok { + panic(fmt.Errorf("a deriver/emitter with name %q already exists", name)) + } + + ctx, cancel := context.WithCancel(context.Background()) + r := &systemActor{ + name: name, + deriv: deriver, + sys: s, + ctx: ctx, + cancel: cancel, + } + s.regs[name] = r + var em Emitter = r + if opts.Emitter.Limiting { + limitedCallback := opts.Emitter.OnLimited + em = NewLimiter(ctx, r, opts.Emitter.Rate, opts.Emitter.Burst, func() { + r.sys.recordRateLimited(name, r.currentEvent) + if limitedCallback != nil { + limitedCallback() + } + }) + } + // If it can emit, attach an emitter to it + if attachTo, ok := deriver.(AttachEmitter); ok { + attachTo.AttachEmitter(em) + } + // If it can derive, add it to the executor (and only after attaching the emitter) + if deriver != nil { + r.leaveExecutor = s.executor.Add(r, &opts.Executor) + } + return em +} + +func (s *Sys) Unregister(name string) (previous Emitter) { + s.regsLock.Lock() + defer s.regsLock.Unlock() + return s.unregister(name) +} + +func (s *Sys) unregister(name string) (previous Emitter) { + r, ok := s.regs[name] + if !ok { + return nil + } + r.cancel() + // if this was registered as deriver with the executor, then leave the executor + if r.leaveExecutor != nil { + r.leaveExecutor() + } + delete(s.regs, name) + return r +} + +// Stop shuts down the system +// by unregistering all emitters/derivers, +// freeing up executor resources. +func (s *Sys) Stop() { + s.regsLock.Lock() + defer s.regsLock.Unlock() + for _, r := range s.regs { + s.unregister(r.name) + } +} + +func (s *Sys) AddTracer(t Tracer) { + s.tracersLock.Lock() + defer s.tracersLock.Unlock() + s.tracers = append(s.tracers, t) +} + +func (s *Sys) RemoveTracer(t Tracer) { + s.tracersLock.Lock() + defer s.tracersLock.Unlock() + // We are not removing tracers often enough to optimize the deletion; + // instead we prefer fast and simple tracer iteration during regular operation. + s.tracers = slices.DeleteFunc(s.tracers, func(v Tracer) bool { + return v == t + }) +} + +// recordDeriv records that the deriver by name [deriv] is processing event [ev]. +// This returns a unique integer (during lifetime of Sys), usable as ID to reference processing. +func (s *Sys) recordDerivStart(name string, ev AnnotatedEvent, startTime time.Time) uint64 { + derivContext := s.derivContext.Add(1) + + s.tracersLock.RLock() + defer s.tracersLock.RUnlock() + for _, t := range s.tracers { + t.OnDeriveStart(name, ev, derivContext, startTime) + } + + return derivContext +} + +func (s *Sys) recordDerivEnd(name string, ev AnnotatedEvent, derivContext uint64, startTime time.Time, duration time.Duration, effect bool) { + s.tracersLock.RLock() + defer s.tracersLock.RUnlock() + for _, t := range s.tracers { + t.OnDeriveEnd(name, ev, derivContext, startTime, duration, effect) + } +} + +func (s *Sys) recordRateLimited(name string, derivContext uint64) { + s.tracersLock.RLock() + defer s.tracersLock.RUnlock() + s.log.Warn("Event-system emitter component was rate-limited", "emitter", name) + for _, t := range s.tracers { + t.OnRateLimited(name, derivContext) + } +} + +func (s *Sys) recordEmit(name string, ev AnnotatedEvent, derivContext uint64, emitTime time.Time) { + s.tracersLock.RLock() + defer s.tracersLock.RUnlock() + for _, t := range s.tracers { + t.OnEmit(name, ev, derivContext, emitTime) + } +} + +// emit an event [ev] during the derivation of another event, referenced by derivContext. +// If the event was emitted not as part of deriver event execution, then the derivContext is 0. +// The name of the emitter is provided to further contextualize the event. +func (s *Sys) emit(name string, derivContext uint64, ev Event) { + emitContext := s.emitContext.Add(1) + annotated := AnnotatedEvent{Event: ev, EmitContext: emitContext} + + emitTime := time.Now() + s.recordEmit(name, annotated, derivContext, emitTime) + + err := s.executor.Enqueue(annotated) + if err != nil { + s.log.Error("Failed to enqueue event", "emitter", name, "event", ev, "context", derivContext) + return + } +} diff --git a/op-node/rollup/event/system_test.go b/op-node/rollup/event/system_test.go new file mode 100644 index 0000000000000..9feef96285319 --- /dev/null +++ b/op-node/rollup/event/system_test.go @@ -0,0 +1,106 @@ +package event + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/ethereum/go-ethereum/log" + + "github.com/ethereum-optimism/optimism/op-service/testlog" +) + +func TestSysTracing(t *testing.T) { + logger := testlog.Logger(t, log.LevelError) + ex := NewGlobalSynchronous(context.Background()) + sys := NewSystem(logger, ex) + count := 0 + foo := DeriverFunc(func(ev Event) bool { + switch ev.(type) { + case TestEvent: + count += 1 + return true + } + return false + }) + lgr, logs := testlog.CaptureLogger(t, log.LevelDebug) + logTracer := NewLogTracer(lgr, log.LevelDebug) + sys.AddTracer(logTracer) + + em := sys.Register("foo", foo, DefaultRegisterOpts()) + em.Emit(TestEvent{}) + require.Equal(t, 0, count, "no event processing before synchronous executor explicitly drains") + require.NoError(t, ex.Drain()) + require.Equal(t, 1, count) + + hasDebugLevel := testlog.NewLevelFilter(log.LevelDebug) + require.NotNil(t, logs.FindLog(hasDebugLevel, + testlog.NewMessageContainsFilter("Emitting event"))) + require.NotNil(t, logs.FindLog(hasDebugLevel, + testlog.NewMessageContainsFilter("Processing event"))) + require.NotNil(t, logs.FindLog(hasDebugLevel, + testlog.NewMessageContainsFilter("Processed event"))) + em.Emit(FooEvent{}) + require.NoError(t, ex.Drain()) + require.Equal(t, 1, count, "foo does not count") + + em.Emit(TestEvent{}) + require.NoError(t, ex.Drain()) + require.Equal(t, 2, count) + + logs.Clear() + sys.RemoveTracer(logTracer) + em.Emit(TestEvent{}) + require.NoError(t, ex.Drain()) + require.Equal(t, 3, count) + require.Equal(t, 0, len(*logs.Logs), "no logs when tracer is not active anymore") +} + +func TestSystemBroadcast(t *testing.T) { + logger := testlog.Logger(t, log.LevelError) + ex := NewGlobalSynchronous(context.Background()) + sys := NewSystem(logger, ex) + fooCount := 0 + foo := DeriverFunc(func(ev Event) bool { + switch ev.(type) { + case TestEvent: + fooCount += 1 + case FooEvent: + fooCount += 1 + default: + return false + } + return true + }) + barCount := 0 + bar := DeriverFunc(func(ev Event) bool { + switch ev.(type) { + case TestEvent: + barCount += 1 + case BarEvent: + barCount += 1 + default: + return false + } + return true + }) + fooEm := sys.Register("foo", foo, DefaultRegisterOpts()) + fooEm.Emit(TestEvent{}) + barEm := sys.Register("bar", bar, DefaultRegisterOpts()) + barEm.Emit(TestEvent{}) + // events are broadcast to every deriver, regardless who sends them + require.NoError(t, ex.Drain()) + require.Equal(t, 2, fooCount) + require.Equal(t, 2, barCount) + // emit from bar, process in foo + barEm.Emit(FooEvent{}) + require.NoError(t, ex.Drain()) + require.Equal(t, 3, fooCount) + require.Equal(t, 2, barCount) + // emit from foo, process in bar + fooEm.Emit(BarEvent{}) + require.NoError(t, ex.Drain()) + require.Equal(t, 3, fooCount) + require.Equal(t, 3, barCount) +} diff --git a/op-node/rollup/event/tracer.go b/op-node/rollup/event/tracer.go new file mode 100644 index 0000000000000..658aa094e2293 --- /dev/null +++ b/op-node/rollup/event/tracer.go @@ -0,0 +1,12 @@ +package event + +import ( + "time" +) + +type Tracer interface { + OnDeriveStart(name string, ev AnnotatedEvent, derivContext uint64, startTime time.Time) + OnDeriveEnd(name string, ev AnnotatedEvent, derivContext uint64, startTime time.Time, duration time.Duration, effect bool) + OnRateLimited(name string, derivContext uint64) + OnEmit(name string, ev AnnotatedEvent, derivContext uint64, emitTime time.Time) +} diff --git a/op-node/rollup/event/tracer_log.go b/op-node/rollup/event/tracer_log.go new file mode 100644 index 0000000000000..483fb9781326a --- /dev/null +++ b/op-node/rollup/event/tracer_log.go @@ -0,0 +1,41 @@ +package event + +import ( + "time" + + "golang.org/x/exp/slog" + + "github.com/ethereum/go-ethereum/log" +) + +type LogTracer struct { + log log.Logger + lvl slog.Level +} + +var _ Tracer = (*LogTracer)(nil) + +func NewLogTracer(log log.Logger, lvl slog.Level) *LogTracer { + return &LogTracer{ + log: log, + lvl: lvl, + } +} + +func (lt *LogTracer) OnDeriveStart(name string, ev AnnotatedEvent, derivContext uint64, startTime time.Time) { + lt.log.Log(lt.lvl, "Processing event", "deriver", name, "event", ev.Event, + "emit_context", ev.EmitContext, "deriv_context", derivContext) +} + +func (lt *LogTracer) OnDeriveEnd(name string, ev AnnotatedEvent, derivContext uint64, startTime time.Time, duration time.Duration, effect bool) { + lt.log.Log(lt.lvl, "Processed event", "deriver", name, "duration", duration, + "event", ev.Event, "emit_context", ev.EmitContext, "deriv_context", derivContext, "effect", effect) +} + +func (lt *LogTracer) OnRateLimited(name string, derivContext uint64) { + lt.log.Log(lt.lvl, "Rate-limited event-emission", "emitter", name, "context", derivContext) +} + +func (lt *LogTracer) OnEmit(name string, ev AnnotatedEvent, derivContext uint64, emitTime time.Time) { + lt.log.Log(lt.lvl, "Emitting event", "emitter", name, "event", ev.Event, "emit_context", ev.EmitContext, "deriv_context", derivContext) +} diff --git a/op-node/rollup/event/tracer_metrics.go b/op-node/rollup/event/tracer_metrics.go new file mode 100644 index 0000000000000..87894d224b6a3 --- /dev/null +++ b/op-node/rollup/event/tracer_metrics.go @@ -0,0 +1,31 @@ +package event + +import "time" + +type MetricsTracer struct { + metrics Metrics +} + +var _ Tracer = (*MetricsTracer)(nil) + +func NewMetricsTracer(m Metrics) *MetricsTracer { + return &MetricsTracer{metrics: m} +} + +func (mt *MetricsTracer) OnDeriveStart(name string, ev AnnotatedEvent, derivContext uint64, startTime time.Time) { +} + +func (mt *MetricsTracer) OnDeriveEnd(name string, ev AnnotatedEvent, derivContext uint64, startTime time.Time, duration time.Duration, effect bool) { + if !effect { // don't count events that were just pass-through and not of any effect + return + } + mt.metrics.RecordProcessedEvent(ev.Event.String(), name, duration) +} + +func (mt *MetricsTracer) OnRateLimited(name string, derivContext uint64) { + mt.metrics.RecordEventsRateLimited() +} + +func (mt *MetricsTracer) OnEmit(name string, ev AnnotatedEvent, derivContext uint64, emitTime time.Time) { + mt.metrics.RecordEmittedEvent(ev.Event.String(), name) +} diff --git a/op-node/rollup/event/tracer_sequence.go b/op-node/rollup/event/tracer_sequence.go new file mode 100644 index 0000000000000..938c0460cdf73 --- /dev/null +++ b/op-node/rollup/event/tracer_sequence.go @@ -0,0 +1,86 @@ +package event + +import ( + "fmt" + "strings" +) + +type SequenceTracer struct { + StructTracer +} + +var _ Tracer = (*SequenceTracer)(nil) + +func NewSequenceTracer() *SequenceTracer { + return &SequenceTracer{} +} + +func (st *SequenceTracer) Output(showDurations bool) string { + st.l.Lock() + defer st.l.Unlock() + out := new(strings.Builder) + out.WriteString(` + + +
+ ++`) + + // Docs: https://mermaid.js.org/syntax/sequenceDiagram.html + _, _ = fmt.Fprintln(out, "sequenceDiagram") + // make sure the System is always the left-most entry in the diagram + _, _ = fmt.Fprintln(out, " participant System") + // other participants are implied by the following events + + denyList := make(map[uint64]struct{}) + for _, e := range st.Entries { + if e.Kind == TraceDeriveEnd && !e.DeriveEnd.Effect { + denyList[e.DerivContext] = struct{}{} + } + } + for _, e := range st.Entries { + // omit entries which just passed through but did not have any effective processing + if e.DerivContext != 0 { + if _, ok := denyList[e.DerivContext]; ok { + continue + } + } + switch e.Kind { + case TraceDeriveStart: + _, _ = fmt.Fprintf(out, " %%%% deriver-start %d\n", e.DerivContext) + _, _ = fmt.Fprintf(out, " System ->> %s: derive %s (%d)\n", e.Name, e.EventName, e.EmitContext) + _, _ = fmt.Fprintf(out, " activate %s\n", e.Name) + case TraceDeriveEnd: + _, _ = fmt.Fprintf(out, " deactivate %s\n", e.Name) + if showDurations { + _, _ = fmt.Fprintf(out, " Note over %s: duration: %s\n", e.Name, strings.ReplaceAll(e.DeriveEnd.Duration.String(), "µ", "#181;")) + } + _, _ = fmt.Fprintf(out, " %%%% deriver-end %d\n", e.DerivContext) + case TraceRateLimited: + _, _ = fmt.Fprintf(out, " Note over %s: rate-limited\n", e.Name) + case TraceEmit: + _, _ = fmt.Fprintf(out, " %%%% emit originates from %d\n", e.DerivContext) + _, _ = fmt.Fprintf(out, " %s -->> System: emit %s (%d)\n", e.Name, e.EventName, e.EmitContext) + _, _ = fmt.Fprintln(out, " activate System") + _, _ = fmt.Fprintln(out, " deactivate System") + } + } + + out.WriteString(` ++ + + + +`) + return out.String() +} diff --git a/op-node/rollup/event/tracer_struct.go b/op-node/rollup/event/tracer_struct.go new file mode 100644 index 0000000000000..b3999153056b3 --- /dev/null +++ b/op-node/rollup/event/tracer_struct.go @@ -0,0 +1,101 @@ +package event + +import ( + "sync" + "time" +) + +type TraceEntryKind int + +const ( + TraceDeriveStart TraceEntryKind = iota + TraceDeriveEnd + TraceRateLimited + TraceEmit +) + +type TraceEntry struct { + Kind TraceEntryKind + + Name string + DerivContext uint64 + + // Not present if Kind == TraceRateLimited + EmitContext uint64 + // Not present if Kind == TraceRateLimited + EventName string + + // Set to deriver start-time if derive-start/end, or emit-time if emitted. Not set if Kind == TraceRateLimited + EventTime time.Time + + // Only present if Kind == TraceDeriveEnd + DeriveEnd struct { + Duration time.Duration + Effect bool + } +} + +type StructTracer struct { + l sync.Mutex + + Entries []TraceEntry +} + +var _ Tracer = (*StructTracer)(nil) + +func NewStructTracer() *StructTracer { + return &StructTracer{} +} + +func (st *StructTracer) OnDeriveStart(name string, ev AnnotatedEvent, derivContext uint64, startTime time.Time) { + st.l.Lock() + defer st.l.Unlock() + st.Entries = append(st.Entries, TraceEntry{ + Kind: TraceDeriveStart, + Name: name, + EventName: ev.Event.String(), + EmitContext: ev.EmitContext, + DerivContext: derivContext, + EventTime: startTime, + }) +} + +func (st *StructTracer) OnDeriveEnd(name string, ev AnnotatedEvent, derivContext uint64, startTime time.Time, duration time.Duration, effect bool) { + st.l.Lock() + defer st.l.Unlock() + st.Entries = append(st.Entries, TraceEntry{ + Kind: TraceDeriveEnd, + Name: name, + EventName: ev.Event.String(), + EmitContext: ev.EmitContext, + DerivContext: derivContext, + EventTime: startTime, + DeriveEnd: struct { + Duration time.Duration + Effect bool + }{Duration: duration, Effect: effect}, + }) +} + +func (st *StructTracer) OnRateLimited(name string, derivContext uint64) { + st.l.Lock() + defer st.l.Unlock() + st.Entries = append(st.Entries, TraceEntry{ + Kind: TraceRateLimited, + Name: name, + DerivContext: derivContext, + }) +} + +func (st *StructTracer) OnEmit(name string, ev AnnotatedEvent, derivContext uint64, emitTime time.Time) { + st.l.Lock() + defer st.l.Unlock() + st.Entries = append(st.Entries, TraceEntry{ + Kind: TraceEmit, + Name: name, + EventName: ev.Event.String(), + EmitContext: ev.EmitContext, + DerivContext: derivContext, + EventTime: emitTime, + }) +} diff --git a/op-node/rollup/event/tracer_timing.go b/op-node/rollup/event/tracer_timing.go new file mode 100644 index 0000000000000..de20481a21b64 --- /dev/null +++ b/op-node/rollup/event/tracer_timing.go @@ -0,0 +1,237 @@ +package event + +import ( + "fmt" + "sort" + "strings" + "time" + + "golang.org/x/exp/maps" +) + +// TimingTracer generates an HTML output with an SVG that shows, +// per deriver, per event-type, bands for event-execution scaled by the execution time. +// This trace gives an idea of patterns between events and where execution-time is spent. +type TimingTracer struct { + StructTracer +} + +var _ Tracer = (*TimingTracer)(nil) + +func NewTimingTracer() *TimingTracer { + return &TimingTracer{} +} + +func (st *TimingTracer) Output() string { + st.l.Lock() + defer st.l.Unlock() + out := new(strings.Builder) + out.WriteString(` + + + + +