diff --git a/kroma-validator/challenger.go b/kroma-validator/challenger.go index 107735c29..f46dd13bc 100644 --- a/kroma-validator/challenger.go +++ b/kroma-validator/challenger.go @@ -49,12 +49,14 @@ type Challenger struct { colosseumABI *abi.ABI valPoolContract *bindings.ValidatorPoolCaller valMgrContract *bindings.ValidatorManagerCaller + assetMgrContract *bindings.AssetManagerCaller submissionInterval *big.Int finalizationPeriodSeconds *big.Int l2BlockTime *big.Int checkpoint *big.Int - requiredBondAmount *big.Int + requiredBondAmountV1 *big.Int + requiredBondAmountV2 *big.Int valPoolTerminationIndex *big.Int l2OutputSubmittedSub ethereum.Subscription @@ -97,6 +99,11 @@ func NewChallenger(cfg Config, l log.Logger, m metrics.Metricer) (*Challenger, e return nil, err } + assetMgrContract, err := bindings.NewAssetManagerCaller(cfg.AssetManagerAddr, cfg.L1Client) + if err != nil { + return nil, err + } + return &Challenger{ log: l.New("service", "challenge"), cfg: cfg, @@ -111,6 +118,7 @@ func NewChallenger(cfg Config, l log.Logger, m metrics.Metricer) (*Challenger, e colosseumABI: colosseumABI, valPoolContract: valPoolContract, valMgrContract: valMgrContract, + assetMgrContract: assetMgrContract, }, nil } @@ -151,18 +159,18 @@ func (c *Challenger) InitConfig(ctx context.Context) error { err = contractWatcher.WatchUpgraded(c.cfg.ValidatorPoolAddr, func() error { cCtx, cCancel := context.WithTimeout(ctx, c.cfg.NetworkTimeout) defer cCancel() - requiredBondAmount, err := c.valPoolContract.REQUIREDBONDAMOUNT(optsutils.NewSimpleCallOpts(cCtx)) + requiredBondAmountV1, err := c.valPoolContract.REQUIREDBONDAMOUNT(optsutils.NewSimpleCallOpts(cCtx)) if err != nil { return fmt.Errorf("failed to get submission interval: %w", err) } - c.requiredBondAmount = requiredBondAmount + c.requiredBondAmountV1 = requiredBondAmountV1 cCtx, cCancel = context.WithTimeout(ctx, c.cfg.NetworkTimeout) defer cCancel() valPoolTerminationIndex, err := c.valPoolContract.TERMINATEOUTPUTINDEX(optsutils.NewSimpleCallOpts(cCtx)) if err != nil { // If method is not in ValidatorPool, set the termination index to big value to ensure it sticks to validator system V1. - if errors.Is(err, ErrMethodNotFound) { + if errors.Is(err, errors.New("method 'TERMINATION_OUTPUT_INDEX' not found")) { valPoolTerminationIndex = big.NewInt(math.MaxUint32) } else { return fmt.Errorf("failed to get valPool termination index: %w", err) @@ -176,6 +184,24 @@ func (c *Challenger) InitConfig(ctx context.Context) error { return fmt.Errorf("failed to initiate valPool config: %w", err) } + err = contractWatcher.WatchUpgraded(c.cfg.AssetManagerAddr, func() error { + cCtx, cCancel := context.WithTimeout(ctx, c.cfg.NetworkTimeout) + defer cCancel() + requiredBondAmountV2, err := c.assetMgrContract.BONDAMOUNT(optsutils.NewSimpleCallOpts(cCtx)) + if err != nil { + if errors.Is(err, errors.New("method 'BOND_AMOUNT' not found")) { + requiredBondAmountV2 = big.NewInt(0) + } + return fmt.Errorf("failed to get required bond amount: %w", err) + } + c.requiredBondAmountV2 = requiredBondAmountV2 + + return nil + }) + if err != nil { + return fmt.Errorf("failed to initiate assetMgr config: %w, err") + } + return nil } @@ -637,6 +663,7 @@ func (c *Challenger) CanCreateChallenge(ctx context.Context, outputIndex *big.In cCtx, cCancel := context.WithTimeout(ctx, c.cfg.NetworkTimeout) defer cCancel() from := c.cfg.TxManager.From() + var balance, requiredBondAmount *big.Int if c.IsValPoolTerminated(outputIndex) { if isInJail, err := c.isInJail(ctx); err != nil { return false, err @@ -655,25 +682,35 @@ func (c *Challenger) CanCreateChallenge(ctx context.Context, outputIndex *big.In c.log.Warn("validator is not in the status that can create a challenge", "status", validatorStatus) return false, nil } + + balance, err = c.assetMgrContract.TotalValidatorBalance(optsutils.NewSimpleCallOpts(cCtx), from) + if err != nil { + return false, fmt.Errorf("failed to fetch balance: %w", err) + } + requiredBondAmount = c.requiredBondAmountV2 } else { - balance, err := c.valPoolContract.BalanceOf(optsutils.NewSimpleCallOpts(cCtx), from) + var err error + balance, err = c.valPoolContract.BalanceOf(optsutils.NewSimpleCallOpts(cCtx), from) if err != nil { return false, fmt.Errorf("failed to fetch deposit amount: %w", err) } - c.metr.RecordDepositAmount(balance) - - if balance.Cmp(c.requiredBondAmount) == -1 { - c.log.Warn( - "deposit is less than bond attempt amount", - "requiredBondAmount", c.requiredBondAmount, - "deposit", balance, - ) - return false, nil - } + requiredBondAmount = c.requiredBondAmountV1 + } - c.log.Info("deposit amount and bond amount", "deposit", balance, "bond", c.requiredBondAmount) + c.metr.RecordDepositAmount(balance) + + // Check if the deposit amount is less than the required bond amount + if balance.Cmp(requiredBondAmount) == -1 { + c.log.Warn( + "deposit is less than bond attempt amount", + "requiredBondAmount", requiredBondAmount, + "deposit", balance, + ) + return false, nil } + c.log.Info("deposit amount and bond amount", "deposit", balance, "bond", requiredBondAmount) + return true, nil } diff --git a/kroma-validator/l2_output_submitter.go b/kroma-validator/l2_output_submitter.go index 47bd90514..b6bc0fb49 100644 --- a/kroma-validator/l2_output_submitter.go +++ b/kroma-validator/l2_output_submitter.go @@ -31,7 +31,6 @@ const ( ) var PublicRoundAddress = common.HexToAddress(publicRoundHex) -var ErrMethodNotFound = errors.New("method 'TERMINATION_OUTPUT_INDEX' not found") // L2OutputSubmitter is responsible for submitting outputs. type L2OutputSubmitter struct { @@ -42,15 +41,16 @@ type L2OutputSubmitter struct { log log.Logger metr metrics.Metricer - l2OOContract *bindings.L2OutputOracleCaller - l2OOABI *abi.ABI - valPoolContract *bindings.ValidatorPoolCaller - valMgrContract *bindings.ValidatorManagerCaller - valMgrAbi *abi.ABI + l2OOContract *bindings.L2OutputOracleCaller + l2OOABI *abi.ABI + valPoolContract *bindings.ValidatorPoolCaller + valMgrContract *bindings.ValidatorManagerCaller + assetMgrContract *bindings.AssetManagerCaller singleRoundInterval *big.Int l2BlockTime *big.Int - requiredBondAmount *big.Int + requiredBondAmountV1 *big.Int + requiredBondAmountV2 *big.Int valPoolTerminationIndex *big.Int submitChan chan struct{} @@ -70,30 +70,30 @@ func NewL2OutputSubmitter(cfg Config, l log.Logger, m metrics.Metricer) (*L2Outp return nil, err } - parsedValMgrAbi, err := bindings.ValidatorManagerMetaData.GetAbi() + valPoolContract, err := bindings.NewValidatorPoolCaller(cfg.ValidatorPoolAddr, cfg.L1Client) if err != nil { return nil, err } - valPoolContract, err := bindings.NewValidatorPoolCaller(cfg.ValidatorPoolAddr, cfg.L1Client) + valMgrContract, err := bindings.NewValidatorManagerCaller(cfg.ValidatorManagerAddr, cfg.L1Client) if err != nil { return nil, err } - valMgrContract, err := bindings.NewValidatorManagerCaller(cfg.ValidatorManagerAddr, cfg.L1Client) + assetMgrContract, err := bindings.NewAssetManagerCaller(cfg.AssetManagerAddr, cfg.L1Client) if err != nil { return nil, err } return &L2OutputSubmitter{ - cfg: cfg, - log: l.New("service", "submitter"), - metr: m, - l2OOContract: l2OOContract, - l2OOABI: parsedL2OOAbi, - valPoolContract: valPoolContract, - valMgrContract: valMgrContract, - valMgrAbi: parsedValMgrAbi, + cfg: cfg, + log: l.New("service", "submitter"), + metr: m, + l2OOContract: l2OOContract, + l2OOABI: parsedL2OOAbi, + valPoolContract: valPoolContract, + valMgrContract: valMgrContract, + assetMgrContract: assetMgrContract, }, nil } @@ -127,18 +127,18 @@ func (l *L2OutputSubmitter) InitConfig(ctx context.Context) error { err = contractWatcher.WatchUpgraded(l.cfg.ValidatorPoolAddr, func() error { cCtx, cCancel := context.WithTimeout(ctx, l.cfg.NetworkTimeout) defer cCancel() - requiredBondAmount, err := l.valPoolContract.REQUIREDBONDAMOUNT(optsutils.NewSimpleCallOpts(cCtx)) + requiredBondAmountV1, err := l.valPoolContract.REQUIREDBONDAMOUNT(optsutils.NewSimpleCallOpts(cCtx)) if err != nil { return fmt.Errorf("failed to get required bond amount: %w", err) } - l.requiredBondAmount = requiredBondAmount + l.requiredBondAmountV1 = requiredBondAmountV1 cCtx, cCancel = context.WithTimeout(ctx, l.cfg.NetworkTimeout) defer cCancel() valPoolTerminationIndex, err := l.valPoolContract.TERMINATEOUTPUTINDEX(optsutils.NewSimpleCallOpts(cCtx)) if err != nil { // If method is not in ValidatorPool, set the termination index to big value to ensure it sticks to validator system V1. - if errors.Is(err, ErrMethodNotFound) { + if errors.Is(err, errors.New("method 'TERMINATION_OUTPUT_INDEX' not found")) { valPoolTerminationIndex = big.NewInt(math.MaxUint32) } else { return fmt.Errorf("failed to get valPool termination index: %w", err) @@ -152,6 +152,24 @@ func (l *L2OutputSubmitter) InitConfig(ctx context.Context) error { return fmt.Errorf("failed to initiate valPool config: %w", err) } + err = contractWatcher.WatchUpgraded(l.cfg.AssetManagerAddr, func() error { + cCtx, cCancel := context.WithTimeout(ctx, l.cfg.NetworkTimeout) + defer cCancel() + requiredBondAmountV2, err := l.assetMgrContract.BONDAMOUNT(optsutils.NewSimpleCallOpts(cCtx)) + if err != nil { + if errors.Is(err, errors.New("method 'BOND_AMOUNT' not found")) { + requiredBondAmountV2 = big.NewInt(0) + } + return fmt.Errorf("failed to get required bond amount: %w", err) + } + l.requiredBondAmountV2 = requiredBondAmountV2 + + return nil + }) + if err != nil { + return fmt.Errorf("failed to initiate assetMgr config: %w, err") + } + return nil } @@ -307,6 +325,8 @@ func (l *L2OutputSubmitter) CalculateWaitTime(ctx context.Context, nextBlockNumb func (l *L2OutputSubmitter) assertCanSubmitOutput(ctx context.Context, outputIndex *big.Int) error { cCtx, cCancel := context.WithTimeout(ctx, l.cfg.NetworkTimeout) defer cCancel() + from := l.cfg.TxManager.From() + var balance, requiredBondAmount *big.Int if l.IsValPoolTerminated(outputIndex) { if isInJail, err := l.IsInJail(ctx); err != nil { return err @@ -325,25 +345,35 @@ func (l *L2OutputSubmitter) assertCanSubmitOutput(ctx context.Context, outputInd l.log.Warn("validator is not in the status to submit output", "currentStatus", validatorStatus) return nil } + + balance, err = l.assetMgrContract.TotalValidatorBalance(optsutils.NewSimpleCallOpts(cCtx), from) + if err != nil { + return fmt.Errorf("failed to fetch balance: %w", err) + } + requiredBondAmount = l.requiredBondAmountV2 } else { - balance, err := l.valPoolContract.BalanceOf(optsutils.NewSimpleCallOpts(cCtx), l.cfg.TxManager.From()) + var err error + balance, err = l.valPoolContract.BalanceOf(optsutils.NewSimpleCallOpts(cCtx), from) if err != nil { return fmt.Errorf("failed to fetch deposit amount: %w", err) } - l.metr.RecordDepositAmount(balance) - - if balance.Cmp(l.requiredBondAmount) == -1 { - l.log.Warn( - "deposit is less than bond attempt amount", - "requiredBondAmount", l.requiredBondAmount, - "deposit", balance, - ) - return nil - } + requiredBondAmount = l.requiredBondAmountV1 + } - l.log.Info("deposit amount and bond amount", "deposit", balance, "bond", l.requiredBondAmount) + l.metr.RecordDepositAmount(balance) + + // Check if the deposit amount is less than the required bond amount + if balance.Cmp(requiredBondAmount) == -1 { + l.log.Warn( + "deposit is less than bond attempt amount", + "requiredBondAmount", requiredBondAmount, + "deposit", balance, + ) + return nil } + l.log.Info("deposit amount and bond amount", "deposit", balance, "bond", requiredBondAmount) + return nil }