Skip to content

Commit

Permalink
fast confirmation
Browse files Browse the repository at this point in the history
  • Loading branch information
amsanghi committed Jun 26, 2024
1 parent d906798 commit 7f5f406
Show file tree
Hide file tree
Showing 3 changed files with 213 additions and 5 deletions.
34 changes: 30 additions & 4 deletions staker/staker.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ type L1ValidatorConfig struct {
ExtraGas uint64 `koanf:"extra-gas" reload:"hot"`
Dangerous DangerousConfig `koanf:"dangerous"`
ParentChainWallet genericconf.WalletConfig `koanf:"parent-chain-wallet"`
EnableFastConfirmation bool `koanf:"enable-fast-confirmation"`

strategy StakerStrategy
gasRefunder common.Address
Expand Down Expand Up @@ -156,6 +157,7 @@ var DefaultL1ValidatorConfig = L1ValidatorConfig{
ExtraGas: 50000,
Dangerous: DefaultDangerousConfig,
ParentChainWallet: DefaultValidatorL1WalletConfig,
EnableFastConfirmation: false,
}

var TestL1ValidatorConfig = L1ValidatorConfig{
Expand All @@ -176,6 +178,7 @@ var TestL1ValidatorConfig = L1ValidatorConfig{
ExtraGas: 50000,
Dangerous: DefaultDangerousConfig,
ParentChainWallet: DefaultValidatorL1WalletConfig,
EnableFastConfirmation: false,
}

var DefaultValidatorL1WalletConfig = genericconf.WalletConfig{
Expand Down Expand Up @@ -204,6 +207,7 @@ func L1ValidatorConfigAddOptions(prefix string, f *flag.FlagSet) {
dataposter.DataPosterConfigAddOptions(prefix+".data-poster", f, dataposter.DefaultDataPosterConfigForValidator)
DangerousConfigAddOptions(prefix+".dangerous", f)
genericconf.WalletConfigAddOptions(prefix+".parent-chain-wallet", f, DefaultL1ValidatorConfig.ParentChainWallet.Pathname)
f.Bool(prefix+".enable-fast-confirmation", DefaultL1ValidatorConfig.EnableFastConfirmation, "enable fast confirmation")
}

type DangerousConfig struct {
Expand Down Expand Up @@ -864,7 +868,7 @@ func (s *Staker) advanceStake(ctx context.Context, info *OurStakerInfo, effectiv
if err != nil {
return fmt.Errorf("error staking on new node: %w", err)
}
return nil
return s.tryFastConfirmation(ctx, action.assertion.AfterState.GlobalState.BlockHash, action.assertion.AfterState.GlobalState.SendRoot)
}

// If we have no stake yet, we'll put one down
Expand All @@ -886,7 +890,7 @@ func (s *Staker) advanceStake(ctx context.Context, info *OurStakerInfo, effectiv
return fmt.Errorf("error placing new stake on new node: %w", err)
}
info.StakeExists = true
return nil
return s.tryFastConfirmation(ctx, action.assertion.AfterState.GlobalState.BlockHash, action.assertion.AfterState.GlobalState.SendRoot)
case existingNodeAction:
info.LatestStakedNode = action.number
info.LatestStakedNodeHash = action.hash
Expand Down Expand Up @@ -914,7 +918,7 @@ func (s *Staker) advanceStake(ctx context.Context, info *OurStakerInfo, effectiv
if err != nil {
return fmt.Errorf("error staking on existing node: %w", err)
}
return nil
return s.tryFastConfirmationNodeNumber(ctx, action.number)
}

// If we have no stake yet, we'll put one down
Expand All @@ -935,12 +939,34 @@ func (s *Staker) advanceStake(ctx context.Context, info *OurStakerInfo, effectiv
return fmt.Errorf("error placing new stake on existing node: %w", err)
}
info.StakeExists = true
return nil
return s.tryFastConfirmationNodeNumber(ctx, action.number)
default:
panic("invalid action type")
}
}

func (s *Staker) tryFastConfirmationNodeNumber(ctx context.Context, number uint64) error {
if !s.config.EnableFastConfirmation {
return nil
}
nodeInfo, err := s.rollup.LookupNode(ctx, number)
if err != nil {
return err
}
return s.tryFastConfirmation(ctx, nodeInfo.AfterState().GlobalState.BlockHash, nodeInfo.AfterState().GlobalState.SendRoot)
}

func (s *Staker) tryFastConfirmation(ctx context.Context, blockHash common.Hash, sendRoot common.Hash) error {
if !s.config.EnableFastConfirmation {
return nil
}
auth, err := s.builder.Auth(ctx)
if err != nil {
return err
}
_, err = s.rollup.FastConfirmNextNode(auth, blockHash, sendRoot)
return err
}
func (s *Staker) createConflict(ctx context.Context, info *StakerInfo) error {
if info.CurrentChallenge != nil {
return nil
Expand Down
182 changes: 182 additions & 0 deletions system_tests/staker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -464,3 +464,185 @@ func stakerTestImpl(t *testing.T, faultyStaker bool, honestStakerInactive bool)
func TestStakersCooperative(t *testing.T) {
stakerTestImpl(t, false, false)
}

func TestFastConfirmation(t *testing.T) {
ctx, cancelCtx := context.WithCancel(context.Background())
defer cancelCtx()
srv := externalsignertest.NewServer(t)
go func() {
if err := srv.Start(); err != nil {
log.Error("Failed to start external signer server:", err)
return
}
}()
var transferGas = util.NormalizeL2GasForL1GasInitial(800_000, params.GWei) // include room for aggregator L1 costs

builder := NewNodeBuilder(ctx).DefaultConfig(t, true)
builder.L2Info = NewBlockChainTestInfo(
t,
types.NewArbitrumSigner(types.NewLondonSigner(builder.chainConfig.ChainID)), big.NewInt(l2pricing.InitialBaseFeeWei*2),
transferGas,
)

builder.nodeConfig.BatchPoster.MaxDelay = -1000 * time.Hour
cleanup := builder.Build(t)
defer cleanup()

addNewBatchPoster(ctx, t, builder, srv.Address)

builder.L1.SendWaitTestTransactions(t, []*types.Transaction{
builder.L1Info.PrepareTxTo("Faucet", &srv.Address, 30000, big.NewInt(1).Mul(big.NewInt(1e18), big.NewInt(1e18)), nil)})

l2node := builder.L2.ConsensusNode
execNode := builder.L2.ExecNode

config := arbnode.ConfigDefaultL1Test()
config.Sequencer = false
config.DelayedSequencer.Enable = false
config.BatchPoster.Enable = false
builder.execConfig.Sequencer.Enable = false

builder.BridgeBalance(t, "Faucet", big.NewInt(1).Mul(big.NewInt(params.Ether), big.NewInt(10000)))

deployAuth := builder.L1Info.GetDefaultTransactOpts("RollupOwner", ctx)

balance := big.NewInt(params.Ether)
balance.Mul(balance, big.NewInt(100))
builder.L1.TransferBalance(t, "Faucet", "Validator", balance, builder.L1Info)
l1auth := builder.L1Info.GetDefaultTransactOpts("Validator", ctx)

valWalletAddrPtr, err := validatorwallet.GetValidatorWalletContract(ctx, l2node.DeployInfo.ValidatorWalletCreator, 0, &l1auth, l2node.L1Reader, true)
Require(t, err)
valWalletAddr := *valWalletAddrPtr
valWalletAddrCheck, err := validatorwallet.GetValidatorWalletContract(ctx, l2node.DeployInfo.ValidatorWalletCreator, 0, &l1auth, l2node.L1Reader, true)
Require(t, err)
if valWalletAddr == *valWalletAddrCheck {
Require(t, err, "didn't cache validator wallet address", valWalletAddr.String(), "vs", valWalletAddrCheck.String())
}

rollup, err := rollupgen.NewRollupAdminLogic(l2node.DeployInfo.Rollup, builder.L1.Client)
Require(t, err)

upgradeExecutor, err := upgrade_executorgen.NewUpgradeExecutor(l2node.DeployInfo.UpgradeExecutor, builder.L1.Client)
Require(t, err, "unable to bind upgrade executor")
rollupABI, err := abi.JSON(strings.NewReader(rollupgen.RollupAdminLogicABI))
Require(t, err, "unable to parse rollup ABI")

setValidatorCalldata, err := rollupABI.Pack("setValidator", []common.Address{valWalletAddr, srv.Address}, []bool{true, true})
Require(t, err, "unable to generate setValidator calldata")
tx, err := upgradeExecutor.ExecuteCall(&deployAuth, l2node.DeployInfo.Rollup, setValidatorCalldata)
Require(t, err, "unable to set validators")
_, err = builder.L1.EnsureTxSucceeded(tx)
Require(t, err)

setMinAssertPeriodCalldata, err := rollupABI.Pack("setMinimumAssertionPeriod", big.NewInt(1))
Require(t, err, "unable to generate setMinimumAssertionPeriod calldata")
tx, err = upgradeExecutor.ExecuteCall(&deployAuth, l2node.DeployInfo.Rollup, setMinAssertPeriodCalldata)
Require(t, err, "unable to set minimum assertion period")
_, err = builder.L1.EnsureTxSucceeded(tx)
Require(t, err)

setAnyTrustFastConfirmerCalldata, err := rollupABI.Pack("setAnyTrustFastConfirmer", valWalletAddr)
Require(t, err, "unable to generate setAnyTrustFastConfirmer calldata")
tx, err = upgradeExecutor.ExecuteCall(&deployAuth, l2node.DeployInfo.Rollup, setAnyTrustFastConfirmerCalldata)
Require(t, err, "unable to set anytrust fast confirmer")
_, err = builder.L1.EnsureTxSucceeded(tx)
Require(t, err)

valConfig := staker.TestL1ValidatorConfig
valConfig.EnableFastConfirmation = true
parentChainID, err := builder.L1.Client.ChainID(ctx)
if err != nil {
t.Fatalf("Failed to get parent chain id: %v", err)
}
dp, err := arbnode.StakerDataposter(
ctx,
rawdb.NewTable(l2node.ArbDB, storage.StakerPrefix),
l2node.L1Reader,
&l1auth, NewFetcherFromConfig(arbnode.ConfigDefaultL1NonSequencerTest()),
nil,
parentChainID,
)
if err != nil {
t.Fatalf("Error creating validator dataposter: %v", err)
}
valWallet, err := validatorwallet.NewContract(dp, nil, l2node.DeployInfo.ValidatorWalletCreator, l2node.DeployInfo.Rollup, l2node.L1Reader, &l1auth, 0, func(common.Address) {}, func() uint64 { return valConfig.ExtraGas })
Require(t, err)
valConfig.Strategy = "MakeNodes"

_, valStack := createTestValidationNode(t, ctx, &valnode.TestValidationConfig)
blockValidatorConfig := staker.TestBlockValidatorConfig

stateless, err := staker.NewStatelessBlockValidator(
l2node.InboxReader,
l2node.InboxTracker,
l2node.TxStreamer,
execNode,
l2node.ArbDB,
nil,
StaticFetcherFrom(t, &blockValidatorConfig),
valStack,
)
Require(t, err)
err = stateless.Start(ctx)
Require(t, err)
stakerA, err := staker.NewStaker(
l2node.L1Reader,
valWallet,
bind.CallOpts{},
valConfig,
nil,
stateless,
nil,
nil,
l2node.DeployInfo.ValidatorUtils,
nil,
)
Require(t, err)
err = stakerA.Initialize(ctx)
if stakerA.Strategy() != staker.WatchtowerStrategy {
err = valWallet.Initialize(ctx)
Require(t, err)
}
Require(t, err)
cfg := arbnode.ConfigDefaultL1NonSequencerTest()
signerCfg, err := externalSignerTestCfg(srv.Address, srv.URL())
if err != nil {
t.Fatalf("Error getting external signer config: %v", err)
}
cfg.Staker.DataPoster.ExternalSigner = *signerCfg

builder.L2Info.GenerateAccount("BackgroundUser")
tx = builder.L2Info.PrepareTx("Faucet", "BackgroundUser", builder.L2Info.TransferGas, balance, nil)
err = builder.L2.Client.SendTransaction(ctx, tx)
Require(t, err)
_, err = builder.L2.EnsureTxSucceeded(tx)
Require(t, err)

// Continually make L2 transactions in a background thread
backgroundTxsCtx, cancelBackgroundTxs := context.WithCancel(ctx)
backgroundTxsShutdownChan := make(chan struct{})
defer (func() {
cancelBackgroundTxs()
<-backgroundTxsShutdownChan
})()
go (func() {
defer close(backgroundTxsShutdownChan)
err := makeBackgroundTxs(backgroundTxsCtx, builder)
if !errors.Is(err, context.Canceled) {
log.Warn("error making background txs", "err", err)
}
})()

latestConfirmBeforeAct, err := rollup.LatestConfirmed(&bind.CallOpts{})
Require(t, err)
tx, err = stakerA.Act(ctx)
Require(t, err)
_, err = builder.L1.EnsureTxSucceeded(tx)
Require(t, err)
latestConfirmAfterAct, err := rollup.LatestConfirmed(&bind.CallOpts{})
Require(t, err)
if latestConfirmAfterAct <= latestConfirmBeforeAct {
Fatal(t, "staker A didn't advance the latest confirmed node")
}
}

0 comments on commit 7f5f406

Please sign in to comment.