mirror of
https://github.com/0glabs/0g-chain.git
synced 2025-04-04 07:45:50 +00:00
117 lines
3.0 KiB
Go
117 lines
3.0 KiB
Go
package keeper
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/0glabs/0g-chain/x/evmutil/types"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
)
|
|
|
|
// sequenceManager implements the SequenceManager interface
|
|
type sequenceManager struct {
|
|
keeper Keeper
|
|
}
|
|
|
|
// NewSequenceManager creates a new sequence manager
|
|
func NewSequenceManager(k Keeper) types.SequenceManager {
|
|
return &sequenceManager{
|
|
keeper: k,
|
|
}
|
|
}
|
|
|
|
// GetNextSequence implements SequenceManager
|
|
func (sm *sequenceManager) GetNextSequence(ctx sdk.Context, addr sdk.AccAddress) (uint64, error) {
|
|
acc := sm.keeper.accountKeeper.GetAccount(ctx, addr)
|
|
if acc == nil {
|
|
return 0, fmt.Errorf("account not found: %s", addr)
|
|
}
|
|
return acc.GetSequence(), nil
|
|
}
|
|
|
|
// ValidateSequence implements SequenceManager
|
|
func (sm *sequenceManager) ValidateSequence(ctx sdk.Context, addr sdk.AccAddress, sequence uint64) error {
|
|
expected, err := sm.GetNextSequence(ctx, addr)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get account sequence: %w", err)
|
|
}
|
|
|
|
if sequence != expected {
|
|
return fmt.Errorf("%w: got %d, expected %d", types.ErrSequenceMismatch, sequence, expected)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// IncrementSequence implements SequenceManager
|
|
func (sm *sequenceManager) IncrementSequence(ctx sdk.Context, addr sdk.AccAddress) error {
|
|
acc := sm.keeper.accountKeeper.GetAccount(ctx, addr)
|
|
if acc == nil {
|
|
return fmt.Errorf("account not found: %s", addr)
|
|
}
|
|
|
|
if err := acc.SetSequence(acc.GetSequence() + 1); err != nil {
|
|
return fmt.Errorf("failed to increment sequence: %w", err)
|
|
}
|
|
|
|
sm.keeper.accountKeeper.SetAccount(ctx, acc)
|
|
return nil
|
|
}
|
|
|
|
// ExecuteWithRetry executes a message with retry mechanism for sequence mismatch
|
|
func (k Keeper) ExecuteWithRetry(
|
|
ctx sdk.Context,
|
|
msg sdk.Msg,
|
|
config types.RetryConfig,
|
|
) error {
|
|
attempt := 0
|
|
backoff := config.BackoffInterval
|
|
|
|
for attempt < config.MaxAttempts {
|
|
err := k.Execute(ctx, msg)
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
|
|
if !isSequenceMismatchError(err) {
|
|
return err
|
|
}
|
|
|
|
// Wait before retry
|
|
time.Sleep(backoff)
|
|
|
|
// Exponential backoff
|
|
backoff = time.Duration(float64(backoff) * 1.5)
|
|
if backoff > config.MaxBackoff {
|
|
backoff = config.MaxBackoff
|
|
}
|
|
|
|
attempt++
|
|
}
|
|
|
|
return fmt.Errorf("%w: sequence mismatch persists", types.ErrMaxRetriesReached)
|
|
}
|
|
|
|
// isSequenceMismatchError checks if an error is a sequence mismatch error
|
|
func isSequenceMismatchError(err error) bool {
|
|
if err == nil {
|
|
return false
|
|
}
|
|
return strings.Contains(err.Error(), "account sequence mismatch")
|
|
}
|
|
|
|
// Execute executes a message
|
|
func (k Keeper) Execute(ctx sdk.Context, msg sdk.Msg) error {
|
|
// Implementation depends on message type
|
|
switch m := msg.(type) {
|
|
case *types.MsgConvertCoinToERC20:
|
|
_, err := k.ConvertCoinToERC20(ctx, sdk.AccAddress(m.Initiator), m.Receiver, *m.Amount)
|
|
return err
|
|
case *types.MsgConvertERC20ToCoin:
|
|
_, err := k.ConvertERC20ToCoin(ctx, m.Initiator, sdk.AccAddress(m.Receiver), m.ZgChainERC20Address, m.Amount)
|
|
return err
|
|
default:
|
|
return fmt.Errorf("unsupported message type: %T", msg)
|
|
}
|
|
} |