Commit 2fcbe4ba authored by Axel Kingsley's avatar Axel Kingsley Committed by GitHub

SuperSystem: Add Emitter Contract - Basic Message Passing (#11956)

* Add Emitter Contract

* Emitter Contract and Bindings

* AddL2RPC without Stopping

* Rename testdata folder to contracts

* update generate.sh

* update solidity and gen script
parent 3c3a3113
This diff is collapsed.
################################################################
# PROFILE: DEFAULT (Local) #
################################################################
[profile.default]
# Compilation settings
src = 'src'
out = 'build'
script = 'scripts'
optimizer = true
optimizer_runs = 999999
remappings = []
extra_output = ['devdoc', 'userdoc', 'metadata', 'storageLayout']
bytecode_hash = 'none'
build_info_path = 'artifacts/build-info'
ast = true
evm_version = "cancun"
# 5159 error code is selfdestruct error code
ignored_error_codes = ["transient-storage", "code-size", "init-code-size", 5159]
# We set the gas limit to max int64 to avoid running out of gas during testing, since the default
# gas limit is 1B and some of our tests require more gas than that, such as `test_callWithMinGas_noLeakageLow_succeeds`.
# We use this gas limit since it was the default gas limit prior to https://github.com/foundry-rs/foundry/pull/8274.
# Due to toml-rs limitations, if you increase the gas limit above this value it must be a string.
gas_limit = 9223372036854775807
# Test / Script Runner Settings
ffi = false
fs_permissions = []
libs = ["node_modules", "lib"]
#!/bin/sh
set -euo
forge build
cd build/emit.sol
cat EmitEvent.json | jq -r '.bytecode.object' > EmitEvent.bin
cat EmitEvent.json | jq '.abi' > EmitEvent.abi
cd ../..
abigen --abi ./build/emit.sol/EmitEvent.abi --bin ./build/emit.sol/EmitEvent.bin --pkg emit --out ./emit.go
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
contract EmitEvent {
// Define an event that logs the emitted data
event DataEmitted(bytes indexed _data);
// Function that takes calldata and emits the data as an event
function emitData(bytes calldata _data) external {
emit DataEmitted(_data);
}
}
[
{
"type": "function",
"name": "emitData",
"inputs": [
{
"name": "data",
"type": "bytes",
"internalType": "bytes"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "event",
"name": "DataEmitted",
"inputs": [
{
"name": "data",
"type": "bytes",
"indexed": true,
"internalType": "bytes"
}
],
"anonymous": false
}
]
0x6080604052348015600e575f80fd5b5060ff8061001b5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c8063d836083e14602a575b5f80fd5b60396035366004607c565b603b565b005b8181604051604992919060e3565b604051908190038120907fe00bbfe6f6f8f1bbed2da38e3f5a139c6f9da594ab248a3cf8b44fc73627772c905f90a25050565b5f8060208385031215608c575f80fd5b823567ffffffffffffffff8082111560a2575f80fd5b818501915085601f83011260b4575f80fd5b81358181111560c1575f80fd5b86602082850101111560d1575f80fd5b60209290920196919550909350505050565b818382375f910190815291905056fea164736f6c6343000819000a
{"abi":[{"type":"function","name":"emitData","inputs":[{"name":"data","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"event","name":"DataEmitted","inputs":[{"name":"data","type":"bytes","indexed":true,"internalType":"bytes"}],"anonymous":false}],"bytecode":{"object":"0x6080604052348015600e575f80fd5b5060ff8061001b5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c8063d836083e14602a575b5f80fd5b60396035366004607c565b603b565b005b8181604051604992919060e3565b604051908190038120907fe00bbfe6f6f8f1bbed2da38e3f5a139c6f9da594ab248a3cf8b44fc73627772c905f90a25050565b5f8060208385031215608c575f80fd5b823567ffffffffffffffff8082111560a2575f80fd5b818501915085601f83011260b4575f80fd5b81358181111560c1575f80fd5b86602082850101111560d1575f80fd5b60209290920196919550909350505050565b818382375f910190815291905056fea164736f6c6343000819000a","sourceMap":"58:275:0:-:0;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x6080604052348015600e575f80fd5b50600436106026575f3560e01c8063d836083e14602a575b5f80fd5b60396035366004607c565b603b565b005b8181604051604992919060e3565b604051908190038120907fe00bbfe6f6f8f1bbed2da38e3f5a139c6f9da594ab248a3cf8b44fc73627772c905f90a25050565b5f8060208385031215608c575f80fd5b823567ffffffffffffffff8082111560a2575f80fd5b818501915085601f83011260b4575f80fd5b81358181111560c1575f80fd5b86602082850101111560d1575f80fd5b60209290920196919550909350505050565b818382375f910190815291905056fea164736f6c6343000819000a","sourceMap":"58:275:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;244:87;;;;;;:::i;:::-;;:::i;:::-;;;319:4;;307:17;;;;;;;:::i;:::-;;;;;;;;;;;;;;;244:87;;:::o;14:591:1:-;84:6;92;145:2;133:9;124:7;120:23;116:32;113:52;;;161:1;158;151:12;113:52;201:9;188:23;230:18;271:2;263:6;260:14;257:34;;;287:1;284;277:12;257:34;325:6;314:9;310:22;300:32;;370:7;363:4;359:2;355:13;351:27;341:55;;392:1;389;382:12;341:55;432:2;419:16;458:2;450:6;447:14;444:34;;;474:1;471;464:12;444:34;519:7;514:2;505:6;501:2;497:15;493:24;490:37;487:57;;;540:1;537;530:12;487:57;571:2;563:11;;;;;593:6;;-1:-1:-1;14:591:1;;-1:-1:-1;;;;14:591:1:o;610:271::-;793:6;785;780:3;767:33;749:3;819:16;;844:13;;;819:16;610:271;-1:-1:-1;610:271:1:o","linkReferences":{}},"methodIdentifiers":{"emitData(bytes)":"d836083e"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.25+commit.b61c2a91\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"DataEmitted\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"emitData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/emit.sol\":\"EmitEvent\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[]},\"sources\":{\"src/emit.sol\":{\"keccak256\":\"0xdee458d231a8b41e5ba097be7258a6da27501fafb2a6f865705953458aecafbf\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://912d125138604114be66c8d044a39ef83861e6dc2d5fe3be32a1a4e014ea2763\",\"dweb:/ipfs/QmUx5NRsTXzujjwU1SXMSNp5Wjys3v5PDLuhdpoAyCy7nx\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.25+commit.b61c2a91"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"bytes","name":"data","type":"bytes","indexed":true}],"type":"event","name":"DataEmitted","anonymous":false},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"stateMutability":"nonpayable","type":"function","name":"emitData"}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":[],"optimizer":{"enabled":true,"runs":999999},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"src/emit.sol":"EmitEvent"},"evmVersion":"cancun","libraries":{}},"sources":{"src/emit.sol":{"keccak256":"0xdee458d231a8b41e5ba097be7258a6da27501fafb2a6f865705953458aecafbf","urls":["bzz-raw://912d125138604114be66c8d044a39ef83861e6dc2d5fe3be32a1a4e014ea2763","dweb:/ipfs/QmUx5NRsTXzujjwU1SXMSNp5Wjys3v5PDLuhdpoAyCy7nx"],"license":"MIT"}},"version":1},"storageLayout":{"storage":[],"types":{}},"userdoc":{"version":1,"kind":"user"},"devdoc":{"version":1,"kind":"dev"},"ast":{"absolutePath":"src/emit.sol","id":17,"exportedSymbols":{"EmitEvent":[16]},"nodeType":"SourceUnit","src":"32:302:0","nodes":[{"id":1,"nodeType":"PragmaDirective","src":"32:24:0","nodes":[],"literals":["solidity","^","0.8",".15"]},{"id":16,"nodeType":"ContractDefinition","src":"58:275:0","nodes":[{"id":5,"nodeType":"EventDefinition","src":"133:38:0","nodes":[],"anonymous":false,"eventSelector":"e00bbfe6f6f8f1bbed2da38e3f5a139c6f9da594ab248a3cf8b44fc73627772c","name":"DataEmitted","nameLocation":"139:11:0","parameters":{"id":4,"nodeType":"ParameterList","parameters":[{"constant":false,"id":3,"indexed":true,"mutability":"mutable","name":"data","nameLocation":"165:4:0","nodeType":"VariableDeclaration","scope":5,"src":"151:18:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":2,"name":"bytes","nodeType":"ElementaryTypeName","src":"151:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"150:20:0"}},{"id":15,"nodeType":"FunctionDefinition","src":"244:87:0","nodes":[],"body":{"id":14,"nodeType":"Block","src":"292:39:0","nodes":[],"statements":[{"eventCall":{"arguments":[{"id":11,"name":"data","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":7,"src":"319:4:0","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes calldata"}],"id":10,"name":"DataEmitted","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":5,"src":"307:11:0","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory)"}},"id":12,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"307:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":13,"nodeType":"EmitStatement","src":"302:22:0"}]},"functionSelector":"d836083e","implemented":true,"kind":"function","modifiers":[],"name":"emitData","nameLocation":"253:8:0","parameters":{"id":8,"nodeType":"ParameterList","parameters":[{"constant":false,"id":7,"mutability":"mutable","name":"data","nameLocation":"277:4:0","nodeType":"VariableDeclaration","scope":15,"src":"262:19:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes"},"typeName":{"id":6,"name":"bytes","nodeType":"ElementaryTypeName","src":"262:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"261:21:0"},"returnParameters":{"id":9,"nodeType":"ParameterList","parameters":[],"src":"292:0:0"},"scope":16,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"EmitEvent","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[16],"name":"EmitEvent","nameLocation":"67:9:0","scope":17,"usedErrors":[],"usedEvents":[5]}],"license":"MIT"},"id":0}
\ No newline at end of file
...@@ -2,6 +2,7 @@ package interop ...@@ -2,6 +2,7 @@ package interop
import ( import (
"context" "context"
"fmt"
"math/big" "math/big"
"testing" "testing"
"time" "time"
...@@ -54,9 +55,6 @@ func TestInteropTrivial(t *testing.T) { ...@@ -54,9 +55,6 @@ func TestInteropTrivial(t *testing.T) {
expectedBalance, _ := big.NewInt(0).SetString("10000000000000000000000000", 10) expectedBalance, _ := big.NewInt(0).SetString("10000000000000000000000000", 10)
require.Equal(t, expectedBalance, bobBalance) require.Equal(t, expectedBalance, bobBalance)
// sleep for a bit to allow the chain to start
time.Sleep(30 * time.Second)
// send a tx from Alice to Bob // send a tx from Alice to Bob
s2.SendL2Tx( s2.SendL2Tx(
chainA, chainA,
...@@ -86,4 +84,17 @@ func TestInteropTrivial(t *testing.T) { ...@@ -86,4 +84,17 @@ func TestInteropTrivial(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
expectedBalance, _ = big.NewInt(0).SetString("10000000000000000000000000", 10) expectedBalance, _ = big.NewInt(0).SetString("10000000000000000000000000", 10)
require.Equal(t, expectedBalance, bobBalance) require.Equal(t, expectedBalance, bobBalance)
s2.DeployEmitterContract(chainA, "Alice")
rec := s2.EmitData(chainA, "Alice", "0x1234567890abcdef")
fmt.Println("Result of emitting event:", rec)
s2.DeployEmitterContract(chainB, "Alice")
rec = s2.EmitData(chainB, "Alice", "0x1234567890abcdef")
fmt.Println("Result of emitting event:", rec)
time.Sleep(10 * time.Second)
} }
...@@ -10,11 +10,13 @@ import ( ...@@ -10,11 +10,13 @@ import (
"testing" "testing"
"time" "time"
emit "github.com/ethereum-optimism/optimism/op-e2e/interop/contracts"
"github.com/ethereum-optimism/optimism/op-e2e/system/helpers" "github.com/ethereum-optimism/optimism/op-e2e/system/helpers"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
...@@ -86,6 +88,12 @@ type SuperSystem interface { ...@@ -86,6 +88,12 @@ type SuperSystem interface {
SendL2Tx(network string, username string, applyTxOpts helpers.TxOptsFn) *types.Receipt SendL2Tx(network string, username string, applyTxOpts helpers.TxOptsFn) *types.Receipt
// get the address for a user on an L2 // get the address for a user on an L2
Address(network string, username string) common.Address Address(network string, username string) common.Address
// Deploy the Emitter Contract, which emits Event Logs
DeployEmitterContract(network string, username string) common.Address
// Use the Emitter Contract to emit an Event Log
EmitData(network string, username string, data string) *types.Receipt
// Access a contract on a network by name
Contract(network string, contractName string) interface{}
} }
// NewSuperSystem creates a new SuperSystem from a recipe. It creates an interopE2ESystem. // NewSuperSystem creates a new SuperSystem from a recipe. It creates an interopE2ESystem.
...@@ -123,6 +131,7 @@ type l2Set struct { ...@@ -123,6 +131,7 @@ type l2Set struct {
batcher *bss.BatcherService batcher *bss.BatcherService
operatorKeys map[devkeys.ChainOperatorRole]ecdsa.PrivateKey operatorKeys map[devkeys.ChainOperatorRole]ecdsa.PrivateKey
userKeys map[string]ecdsa.PrivateKey userKeys map[string]ecdsa.PrivateKey
contracts map[string]interface{}
} }
// prepareHDWallet creates a new HD wallet to derive keys from // prepareHDWallet creates a new HD wallet to derive keys from
...@@ -401,6 +410,7 @@ func (s *interopE2ESystem) newL2(id string, l2Out *interopgen.L2Output) l2Set { ...@@ -401,6 +410,7 @@ func (s *interopE2ESystem) newL2(id string, l2Out *interopgen.L2Output) l2Set {
batcher: batcher, batcher: batcher,
operatorKeys: operatorKeys, operatorKeys: operatorKeys,
userKeys: make(map[string]ecdsa.PrivateKey), userKeys: make(map[string]ecdsa.PrivateKey),
contracts: make(map[string]interface{}),
} }
} }
...@@ -591,12 +601,60 @@ func (s *interopE2ESystem) SendL2Tx( ...@@ -591,12 +601,60 @@ func (s *interopE2ESystem) SendL2Tx(
) *types.Receipt { ) *types.Receipt {
senderSecret := s.UserKey(id, sender) senderSecret := s.UserKey(id, sender)
require.NotNil(s.t, senderSecret, "no secret found for sender %s", sender) require.NotNil(s.t, senderSecret, "no secret found for sender %s", sender)
nonce, err := s.L2GethClient(id).PendingNonceAt(context.Background(), crypto.PubkeyToAddress(senderSecret.PublicKey))
require.NoError(s.t, err, "failed to get nonce")
newApply := func(opts *helpers.TxOpts) {
applyTxOpts(opts)
opts.Nonce = nonce
}
return helpers.SendL2TxWithID( return helpers.SendL2TxWithID(
s.t, s.t,
s.l2s[id].chainID, s.l2s[id].chainID,
s.L2GethClient(id), s.L2GethClient(id),
&senderSecret, &senderSecret,
applyTxOpts) newApply)
}
func (s *interopE2ESystem) DeployEmitterContract(
id string,
sender string,
) common.Address {
secret := s.UserKey(id, sender)
auth, err := bind.NewKeyedTransactorWithChainID(&secret, s.l2s[id].chainID)
require.NoError(s.t, err)
auth.GasLimit = uint64(3000000)
auth.GasPrice = big.NewInt(20000000000)
address, _, _, err := emit.DeployEmit(auth, s.L2GethClient(id))
require.NoError(s.t, err)
contract, err := emit.NewEmit(address, s.L2GethClient(id))
require.NoError(s.t, err)
s.l2s[id].contracts["emitter"] = contract
return address
}
func (s *interopE2ESystem) EmitData(
id string,
sender string,
data string,
) *types.Receipt {
secret := s.UserKey(id, sender)
auth, err := bind.NewKeyedTransactorWithChainID(&secret, s.l2s[id].chainID)
require.NoError(s.t, err)
auth.GasLimit = uint64(3000000)
auth.GasPrice = big.NewInt(20000000000)
contract := s.Contract(id, "emitter").(*emit.Emit)
tx, err := contract.EmitTransactor.EmitData(auth, []byte(data))
require.NoError(s.t, err)
receipt, err := bind.WaitMined(context.Background(), s.L2GethClient(id), tx)
require.NoError(s.t, err)
return receipt
}
func (s *interopE2ESystem) Contract(id string, name string) interface{} {
return s.l2s[id].contracts[name]
} }
func mustDial(t *testing.T, logger log.Logger) func(v string) *rpc.Client { func mustDial(t *testing.T, logger log.Logger) func(v string) *rpc.Client {
......
...@@ -68,8 +68,9 @@ func NewSupervisorBackend(ctx context.Context, logger log.Logger, m Metrics, cfg ...@@ -68,8 +68,9 @@ func NewSupervisorBackend(ctx context.Context, logger log.Logger, m Metrics, cfg
} }
// from the RPC strings, have the supervisor backend create a chain monitor // from the RPC strings, have the supervisor backend create a chain monitor
// don't start the monitor yet, as we will start all monitors at once when Start is called
for _, rpc := range cfg.L2RPCs { for _, rpc := range cfg.L2RPCs {
err := super.addFromRPC(ctx, logger, rpc) err := super.addFromRPC(ctx, logger, rpc, false)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to add chain monitor for rpc %v: %w", rpc, err) return nil, fmt.Errorf("failed to add chain monitor for rpc %v: %w", rpc, err)
} }
...@@ -79,7 +80,8 @@ func NewSupervisorBackend(ctx context.Context, logger log.Logger, m Metrics, cfg ...@@ -79,7 +80,8 @@ func NewSupervisorBackend(ctx context.Context, logger log.Logger, m Metrics, cfg
// addFromRPC adds a chain monitor to the supervisor backend from an rpc endpoint // addFromRPC adds a chain monitor to the supervisor backend from an rpc endpoint
// it does not expect to be called after the backend has been started // it does not expect to be called after the backend has been started
func (su *SupervisorBackend) addFromRPC(ctx context.Context, logger log.Logger, rpc string) error { // it will start the monitor if shouldStart is true
func (su *SupervisorBackend) addFromRPC(ctx context.Context, logger log.Logger, rpc string, shouldStart bool) error {
// create the rpc client, which yields the chain id // create the rpc client, which yields the chain id
rpcClient, chainID, err := createRpcClient(ctx, logger, rpc) rpcClient, chainID, err := createRpcClient(ctx, logger, rpc)
if err != nil { if err != nil {
...@@ -96,12 +98,18 @@ func (su *SupervisorBackend) addFromRPC(ctx context.Context, logger log.Logger, ...@@ -96,12 +98,18 @@ func (su *SupervisorBackend) addFromRPC(ctx context.Context, logger log.Logger,
if err != nil { if err != nil {
return fmt.Errorf("failed to create logdb for chain %v at %v: %w", chainID, path, err) return fmt.Errorf("failed to create logdb for chain %v at %v: %w", chainID, path, err)
} }
if su.chainMonitors[chainID] != nil {
return fmt.Errorf("chain monitor for chain %v already exists", chainID)
}
monitor, err := source.NewChainMonitor(ctx, logger, cm, chainID, rpc, rpcClient, su.db) monitor, err := source.NewChainMonitor(ctx, logger, cm, chainID, rpc, rpcClient, su.db)
if err != nil { if err != nil {
return fmt.Errorf("failed to create monitor for rpc %v: %w", rpc, err) return fmt.Errorf("failed to create monitor for rpc %v: %w", rpc, err)
} }
if su.chainMonitors[chainID] != nil { // start the monitor if requested
return fmt.Errorf("chain monitor for chain %v already exists", chainID) if shouldStart {
if err := monitor.Start(); err != nil {
return fmt.Errorf("failed to start monitor for rpc %v: %w", rpc, err)
}
} }
su.chainMonitors[chainID] = monitor su.chainMonitors[chainID] = monitor
su.db.AddLogDB(chainID, logDB) su.db.AddLogDB(chainID, logDB)
...@@ -172,15 +180,8 @@ func (su *SupervisorBackend) Close() error { ...@@ -172,15 +180,8 @@ func (su *SupervisorBackend) Close() error {
// AddL2RPC adds a new L2 chain to the supervisor backend // AddL2RPC adds a new L2 chain to the supervisor backend
// it stops and restarts the backend to add the new chain // it stops and restarts the backend to add the new chain
func (su *SupervisorBackend) AddL2RPC(ctx context.Context, rpc string) error { func (su *SupervisorBackend) AddL2RPC(ctx context.Context, rpc string) error {
if err := su.Stop(ctx); err != nil { // start the monitor immediately, as the backend is assumed to already be running
return fmt.Errorf("failed to stop backend: %w", err) return su.addFromRPC(ctx, su.logger, rpc, true)
}
su.logger.Info("temporarily stopped the backend to add a new L2 RPC", "rpc", rpc)
if err := su.addFromRPC(ctx, su.logger, rpc); err != nil {
return fmt.Errorf("failed to add chain monitor: %w", err)
}
su.logger.Info("added the new L2 RPC, starting supervisor again", "rpc", rpc)
return su.Start(ctx)
} }
func (su *SupervisorBackend) CheckMessage(identifier types.Identifier, payloadHash common.Hash) (types.SafetyLevel, error) { func (su *SupervisorBackend) CheckMessage(identifier types.Identifier, payloadHash common.Hash) (types.SafetyLevel, error) {
......
...@@ -48,9 +48,10 @@ type ChainsDB struct { ...@@ -48,9 +48,10 @@ type ChainsDB struct {
func NewChainsDB(logDBs map[types.ChainID]LogStorage, heads HeadsStorage, l log.Logger) *ChainsDB { func NewChainsDB(logDBs map[types.ChainID]LogStorage, heads HeadsStorage, l log.Logger) *ChainsDB {
return &ChainsDB{ return &ChainsDB{
logDBs: logDBs, logDBs: logDBs,
heads: heads, heads: heads,
logger: l, logger: l,
maintenanceReady: make(chan struct{}, 1),
} }
} }
...@@ -79,7 +80,7 @@ func (db *ChainsDB) Resume() error { ...@@ -79,7 +80,7 @@ func (db *ChainsDB) Resume() error {
func (db *ChainsDB) StartCrossHeadMaintenance(ctx context.Context) { func (db *ChainsDB) StartCrossHeadMaintenance(ctx context.Context) {
go func() { go func() {
db.logger.Info("cross-head maintenance loop started") db.logger.Info("cross-head maintenance loop started")
// run the maintenance loop every 10 seconds for now // run the maintenance loop every 1 seconds for now
ticker := time.NewTicker(time.Second * 1) ticker := time.NewTicker(time.Second * 1)
for { for {
select { select {
...@@ -200,8 +201,7 @@ func (db *ChainsDB) UpdateCrossHeadsForChain(chainID types.ChainID, checker Safe ...@@ -200,8 +201,7 @@ func (db *ChainsDB) UpdateCrossHeadsForChain(chainID types.ChainID, checker Safe
// based on the provided SafetyChecker. The SafetyChecker is used to determine // based on the provided SafetyChecker. The SafetyChecker is used to determine
// the safety of each log entry in the database, and the cross-head associated with it. // the safety of each log entry in the database, and the cross-head associated with it.
func (db *ChainsDB) UpdateCrossHeads(checker SafetyChecker) error { func (db *ChainsDB) UpdateCrossHeads(checker SafetyChecker) error {
currentHeads := db.heads.Current() for chainID := range db.logDBs {
for chainID := range currentHeads.Chains {
err := db.UpdateCrossHeadsForChain(chainID, checker) err := db.UpdateCrossHeadsForChain(chainID, checker)
if err != nil { if err != nil {
return err return err
......
...@@ -54,7 +54,7 @@ func NewEntryDB(logger log.Logger, path string) (*EntryDB, error) { ...@@ -54,7 +54,7 @@ func NewEntryDB(logger log.Logger, path string) (*EntryDB, error) {
lastEntryIdx: EntryIdx(size - 1), lastEntryIdx: EntryIdx(size - 1),
} }
if size*EntrySize != info.Size() { if size*EntrySize != info.Size() {
logger.Warn("File size is nut a multiple of entry size. Truncating to last complete entry", "fileSize", size, "entrySize", EntrySize) logger.Warn("File size is not a multiple of entry size. Truncating to last complete entry", "fileSize", size, "entrySize", EntrySize)
if err := db.recover(); err != nil { if err := db.recover(); err != nil {
return nil, fmt.Errorf("failed to recover database at %v: %w", path, err) return nil, fmt.Errorf("failed to recover database at %v: %w", path, err)
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment