Skip to content

Commit

Permalink
Use light client as the trigger
Browse files Browse the repository at this point in the history
  • Loading branch information
ImJeremyHe committed Apr 9, 2024
1 parent e955c49 commit 3ed015e
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 63 deletions.
13 changes: 5 additions & 8 deletions arbnode/batch_poster.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/ethereum/go-ethereum/rpc"

hotshotClient "github.com/EspressoSystems/espresso-sequencer-go/client"
lightclient "github.com/EspressoSystems/espresso-sequencer-go/light-client"

"github.com/offchainlabs/nitro/arbnode/dataposter"
"github.com/offchainlabs/nitro/arbnode/dataposter/storage"
Expand Down Expand Up @@ -75,10 +76,6 @@ type batchPosterPosition struct {
NextSeqNum uint64
}

type LightClientReaderInterface interface {
ValidatedHeight() (validatedHeight uint64, l1Height uint64, err error)
}

type BatchPoster struct {
stopwaiter.StopWaiter
l1Reader *headerreader.HeaderReader
Expand Down Expand Up @@ -111,7 +108,7 @@ type BatchPoster struct {
accessList func(SequencerInboxAccs, AfterDelayedMessagesRead int) types.AccessList

// Espresso readers
lightClientReader LightClientReaderInterface
lightClientReader lightclient.LightClientReaderInterface
hotshotClient *hotshotClient.Client
}

Expand Down Expand Up @@ -314,17 +311,17 @@ func NewBatchPoster(ctx context.Context, opts *BatchPosterOpts) (*BatchPoster, e
return nil, err
}
var hotShotClient *hotshotClient.Client
var lightClientReader LightClientReaderInterface
var lightClientReader lightclient.LightClientReaderInterface

hotShotUrl := opts.Config().HotShotUrl
lightClientAddr := opts.Config().LightClientAddress

if hotShotUrl != "" {
hotShotClient = hotshotClient.NewClient(log.New(), hotShotUrl)
hotShotClient = hotshotClient.NewClient(hotShotUrl)
}

if lightClientAddr != "" {
lightClientReader, err = NewMockLightClientReader(common.HexToAddress(lightClientAddr), opts.L1Reader.Client())
lightClientReader, err = arbos.NewMockLightClientReader(common.HexToAddress(lightClientAddr), opts.L1Reader.Client())
if err != nil {
return nil, err
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package arbnode
package arbos

import (
"time"

"github.com/EspressoSystems/espresso-sequencer-go/types"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
)
Expand All @@ -17,3 +20,11 @@ func NewMockLightClientReader(lightClientAddr common.Address, l1client bind.Cont
func (l *MockLightClientReader) ValidatedHeight() (validatedHeight uint64, l1Height uint64, err error) {
return 18446744073709551615, 18446744073709551615, nil
}

func (l *MockLightClientReader) IsHotShotAvaliable(t time.Duration) bool {
return true
}

func (l *MockLightClientReader) FetchMerkleRootAtL1Block(L1BlockHeight uint64) (types.BlockMerkleRoot, error) {
return types.BlockMerkleRoot{}, nil
}
2 changes: 1 addition & 1 deletion execution/gethexec/espresso_sequencer.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type HotShotState struct {

func NewHotShotState(log log.Logger, url string, startBlock uint64) *HotShotState {
return &HotShotState{
client: *espressoClient.NewClient(log, url),
client: *espressoClient.NewClient(url),
nextSeqBlockNum: startBlock,
}
}
Expand Down
2 changes: 1 addition & 1 deletion execution/gethexec/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ func CreateExecutionNode(
if err != nil {
return nil, err
}
switchSequencer, err := NewSwitchSequencer(sequencer, espressoSequencer, seqConfigFetcher)
switchSequencer, err := NewSwitchSequencer(sequencer, espressoSequencer, parentChainReader.Client(), seqConfigFetcher)
if err != nil {
return nil, err
}
Expand Down
19 changes: 9 additions & 10 deletions execution/gethexec/sequencer.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,13 @@ type SequencerConfig struct {
NonceFailureCacheExpiry time.Duration `koanf:"nonce-failure-cache-expiry" reload:"hot"`

// Espresso specific flags
Espresso bool `koanf:"espresso"`
HotShotUrl string `koanf:"hotshot-url"`
EspressoNamespace uint64 `koanf:"espresso-namespace"`
StartHotShotBlock uint64 `koanf:"start-hotshot-block"`
MaxHotshotDriftTime time.Duration `koanf:"max-hotshot-drift-time"`
ConsecutiveHotshotBlocks int `koanf:"consecutive-hotshot-blocks"`
HotshotTimeFrame time.Duration `koanf:"hotshot-time-frame"`
Espresso bool `koanf:"espresso"`
HotShotUrl string `koanf:"hotshot-url"`
LightClientAddress string `koanf:"light-client-address"`
EspressoNamespace uint64 `koanf:"espresso-namespace"`
StartHotShotBlock uint64 `koanf:"start-hotshot-block"`
MaxHotShotDriftTime time.Duration `koanf:"max-hotshot-drift-time"`
SwitchPollInterval time.Duration `koanf:"switch-poll-interval"`
}

func (c *SequencerConfig) Validate() error {
Expand Down Expand Up @@ -141,9 +141,8 @@ func SequencerConfigAddOptions(prefix string, f *flag.FlagSet) {
f.String(prefix+".hotshot-url", DefaultSequencerConfig.HotShotUrl, "")
f.Uint64(prefix+".espresso-namespace", DefaultSequencerConfig.EspressoNamespace, "espresso namespace that corresponds the L2 chain")
f.Uint64(prefix+".start-hotshot-block", DefaultSequencerConfig.StartHotShotBlock, "the starting block number of hotshot")
f.Duration(prefix+".max-hotshot-drift-time", DefaultSequencerConfig.MaxHotshotDriftTime, "maximum drift time of hotshot")
f.Int(prefix+".consecutive-hotshot-blocks", DefaultSequencerConfig.ConsecutiveHotshotBlocks, "required minimum blocks created by hotshot within the `hotshot-time-frame` before switching to espresso mode")
f.Duration(prefix+".hotshot-time-frame", DefaultSequencerConfig.HotshotTimeFrame, "interval of checking if espresso mode is available or not")
f.Duration(prefix+".max-hotshot-drift-time", DefaultSequencerConfig.MaxHotShotDriftTime, "maximum drift time of hotshot")
f.Duration(prefix+".switch-poll-interval", DefaultSequencerConfig.SwitchPollInterval, "the poll interval of checking the sequencer should be switched or not")
}

type txQueueItem struct {
Expand Down
59 changes: 28 additions & 31 deletions execution/gethexec/switch_sequencer.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ import (
"context"
"time"

lightClient "github.com/EspressoSystems/espresso-sequencer-go/light-client"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/arbitrum_types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/offchainlabs/nitro/arbos"
"github.com/offchainlabs/nitro/util/stopwaiter"
)

Expand All @@ -20,28 +24,31 @@ type SwitchSequencer struct {
centralized *Sequencer
espresso *EspressoSequencer

mode int
maxHotshotDirftTime time.Duration
consecutiveHotshotBlocks int
hotshotTimeFrame time.Duration
maxHotShotDriftTime time.Duration
switchPollInterval time.Duration
lightClient lightClient.LightClientReaderInterface

lastSeenHotShotBlock uint64
mode int
}

func NewSwitchSequencer(centralized *Sequencer, espresso *EspressoSequencer, configFetcher SequencerConfigFetcher) (*SwitchSequencer, error) {
func NewSwitchSequencer(centralized *Sequencer, espresso *EspressoSequencer, l1client bind.ContractBackend, configFetcher SequencerConfigFetcher) (*SwitchSequencer, error) {
config := configFetcher()
if err := config.Validate(); err != nil {
return nil, err
}

lightClient, err := arbos.NewMockLightClientReader(common.HexToAddress(config.LightClientAddress), l1client)
if err != nil {
return nil, err
}

return &SwitchSequencer{
centralized: centralized,
espresso: espresso,
mode: SequencingMode_Espresso,
maxHotshotDirftTime: config.MaxHotshotDriftTime,
consecutiveHotshotBlocks: config.ConsecutiveHotshotBlocks,
hotshotTimeFrame: config.HotshotTimeFrame,
lastSeenHotShotBlock: 0,
centralized: centralized,
espresso: espresso,
lightClient: lightClient,
mode: SequencingMode_Espresso,
maxHotShotDriftTime: config.MaxHotShotDriftTime,
switchPollInterval: config.SwitchPollInterval,
}, nil
}

Expand Down Expand Up @@ -92,29 +99,19 @@ func (s *SwitchSequencer) Start(ctx context.Context) error {
return err
}
s.CallIteratively(func(ctx context.Context) time.Duration {
now := time.Now()
if s.IsRunningEspressoMode() {
if s.espresso.lastCreated.Add(s.maxHotshotDirftTime).Before(now) {
_ = s.SwitchToCentralized(ctx)
}
return s.hotshotTimeFrame
espresso := s.lightClient.IsHotShotAvaliable(s.maxHotShotDriftTime)

var err error
if s.IsRunningEspressoMode() && !espresso {
err = s.SwitchToCentralized(ctx)
} else if !s.IsRunningEspressoMode() && espresso {
err = s.SwitchToEspresso(ctx)
}

b, err := s.espresso.hotShotState.client.FetchLatestBlockHeight(ctx)
if err != nil {
return 100 * time.Second
}
if s.lastSeenHotShotBlock == 0 {
s.lastSeenHotShotBlock = b
return s.hotshotTimeFrame
}
if b-s.lastSeenHotShotBlock <= uint64(s.consecutiveHotshotBlocks) {
s.lastSeenHotShotBlock = 0
_ = s.SwitchToEspresso(ctx)
return 0
}
s.lastSeenHotShotBlock = b
return s.hotshotTimeFrame
return s.switchPollInterval
})

return nil
Expand Down
28 changes: 19 additions & 9 deletions system_tests/espresso_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,16 +307,12 @@ func waitForWith(
}
}

func TestEspressoE2E(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// We run one L1 node, two L2 nodes and the espresso containers in this function.
func runNodes(ctx context.Context, t *testing.T) (*NodeBuilder, *TestClient, *BlockchainTestInfo, func()) {

cleanValNode := createValidationNode(ctx, t, false)
defer cleanValNode()

builder, cleanup := createL1ValidatorPosterNode(ctx, t, hotShotUrl)
defer cleanup()
node := builder.L2

err := waitFor(t, ctx, func() bool {
if e := exec.Command(
Expand All @@ -336,10 +332,8 @@ func TestEspressoE2E(t *testing.T) {
Require(t, err)

cleanEspresso := runEspresso(t, ctx)
defer cleanEspresso()

l2Node, l2Info, cleanL2Node := createL2Node(ctx, t, hotShotUrl, builder)
defer cleanL2Node()

// wait for the commitment task
err = waitForWith(t, ctx, 60*time.Second, 1*time.Second, func() bool {
Expand All @@ -352,9 +346,25 @@ func TestEspressoE2E(t *testing.T) {
})
Require(t, err)

return builder, l2Node, l2Info, func() {
cleanL2Node()
cleanEspresso()
cleanup()
cleanValNode()
}
}

func TestEspressoE2E(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

builder, l2Node, l2Info, cleanup := runNodes(ctx, t)
defer cleanup()
node := builder.L2

// Wait for the initial message
expected := arbutil.MessageIndex(1)
err = waitFor(t, ctx, func() bool {
err := waitFor(t, ctx, func() bool {
msgCnt, err := l2Node.ConsensusNode.TxStreamer.GetMessageCount()
if err != nil {
panic(err)
Expand Down
14 changes: 12 additions & 2 deletions system_tests/espresso_switch_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
package arbtest

import "testing"
import (
"context"
"testing"
)

func TestEspressoSwitch(t *testing.T) {}
func TestEspressoSwitch(t *testing.T) {

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

builder, l2Node, l2Info, cleanup := runNodes(ctx, t)
defer cleanup()
}

0 comments on commit 3ed015e

Please sign in to comment.