From d2bb0bfed51737a727e6fd29702a4539789e7009 Mon Sep 17 00:00:00 2001 From: corver Date: Tue, 3 Sep 2024 19:23:59 +0200 Subject: [PATCH] chore(*): bump golangci-lint (#1799) Bump golangci-lint from v1.50.1 to v1.60.3 Add `ToInt*` int conversion functions to `umath` package. issue: none --------- Co-authored-by: Aayush Rajasekaran --- .github/workflows/golangci-lint.yml | 2 +- .golangci.yml | 2 + .pre-commit-config.yaml | 2 +- cli/cmd/staking.go | 3 +- e2e/app/erc20faucet.go | 3 +- e2e/docker/data.go | 4 +- e2e/fbproxy/app/middleware.go | 4 +- e2e/test/attestations_test.go | 2 +- e2e/test/portals_test.go | 2 +- e2e/vmcompose/data.go | 6 +- go.mod | 2 +- halo/app/start.go | 2 +- halo/attest/keeper/helper.go | 16 ++++ halo/attest/keeper/keeper.go | 4 +- halo/attest/keeper/query.go | 15 ++- halo/cmd/flags.go | 2 +- .../testdata/TestCLIReference_rollback.golden | 2 +- halo/cmd/testdata/TestCLIReference_run.golden | 2 +- halo/config/config.go | 2 +- halo/evmupgrade/evmupgrade.go | 11 ++- halo/genutil/evm/evm.go | 3 +- lib/buildinfo/buildinfo.go | 2 +- lib/cchain/provider/abci.go | 7 +- lib/ethclient/enginemock.go | 13 +-- lib/fireblocks/jsonhttp.go | 2 +- lib/netconf/provider.go | 20 ++-- lib/stream/stream.go | 25 ++--- lib/tracer/rooted.go | 2 +- lib/txmgr/config.go | 9 +- lib/txmgr/txmgr.go | 6 +- lib/umath/umath.go | 74 +++++++++++++++ lib/umath/umath_test.go | 91 +++++++++++++++++++ lib/xchain/provider/fetch.go | 15 ++- monitor/app/sync.go | 13 +-- monitor/xfeemngr/gasprice/mock.go | 4 +- relayer/app/sender.go | 2 +- relayer/app/worker.go | 2 +- 37 files changed, 297 insertions(+), 81 deletions(-) create mode 100644 lib/umath/umath_test.go diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 53624027e..9bcb3c5ad 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -17,6 +17,6 @@ jobs: - name: Run golangci-lint uses: golangci/golangci-lint-action@v3 with: - version: v1.59.1 + version: v1.60.3 # Verbose with color. Just fail, don't fix issues. Use both annotations and normal output. args: -v --color=always --fix=false --out-format=colored-line-number,github-actions diff --git a/.golangci.yml b/.golangci.yml index 44c57a115..440480bd8 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -148,6 +148,7 @@ linters: - ireturn # Too many false positives - mnd # Too many false positives - prealloc # Too many false positives + - predeclared # Too strict - tagliatelle # Too strict - varnamelen # False positives - wsl # Way to strict and opinionated @@ -155,3 +156,4 @@ linters: # Disable deprecated/archived linters (alphabetical order) - execinquery + - exportloopref diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8c7c5ac21..f72353dc1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -33,7 +33,7 @@ repos: # Then run code validators (on the formatted code) - repo: https://github.com/golangci/golangci-lint # See .golangci.yml for config - rev: v1.59.1 + rev: v1.60.3 hooks: - id: golangci-lint require_serial: true # Don't run this in parallel diff --git a/cli/cmd/staking.go b/cli/cmd/staking.go index 2e52f4721..f72face86 100644 --- a/cli/cmd/staking.go +++ b/cli/cmd/staking.go @@ -17,6 +17,7 @@ import ( "github.com/omni-network/omni/lib/evmchain" "github.com/omni-network/omni/lib/log" "github.com/omni-network/omni/lib/netconf" + "github.com/omni-network/omni/lib/umath" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -169,7 +170,7 @@ func createValidator(ctx context.Context, cfg createValConfig) error { if err != nil { return err } - txOpts.Value = new(big.Int).Mul(big.NewInt(int64(cfg.SelfDelegation)), big.NewInt(params.Ether)) // Send self-delegation + txOpts.Value = new(big.Int).Mul(umath.NewBigInt(cfg.SelfDelegation), big.NewInt(params.Ether)) // Send self-delegation consPubkey, err := cfg.ConsensusPubKey() if err != nil { diff --git a/e2e/app/erc20faucet.go b/e2e/app/erc20faucet.go index 09fe8e9d8..8edf97d68 100644 --- a/e2e/app/erc20faucet.go +++ b/e2e/app/erc20faucet.go @@ -10,6 +10,7 @@ import ( "github.com/omni-network/omni/lib/errors" "github.com/omni-network/omni/lib/log" "github.com/omni-network/omni/lib/netconf" + "github.com/omni-network/omni/lib/umath" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/params" @@ -41,7 +42,7 @@ func RunERC20Faucet(ctx context.Context, def Definition, cfg RunERC20FaucetConfi network := networkFromDef(def) addr := common.HexToAddress(cfg.AddrToFund) tokenAddr := contracts.Token(networkID) - amt := new(big.Int).Mul(big.NewInt(int64(cfg.Amount)), big.NewInt(params.Ether)) + amt := new(big.Int).Mul(umath.NewBigInt(cfg.Amount), big.NewInt(params.Ether)) funder, err := omnitoken.InitialSupplyRecipient(networkID) if err != nil { diff --git a/e2e/docker/data.go b/e2e/docker/data.go index 3c0db3ff7..f6de40bc3 100644 --- a/e2e/docker/data.go +++ b/e2e/docker/data.go @@ -13,7 +13,7 @@ import ( const ( ipPrefix = "10.186.73." // See github.com/cometbft/cometbft/test/e2e/pkg for reference startIPSuffix = 100 - startPort = 8000 + startPort = uint32(8000) ) var localhost = net.ParseIP("127.0.0.1") //nolint:gochecknoglobals // Static IP @@ -37,7 +37,7 @@ func NewInfraData(manifest types.Manifest) (types.InfrastructureData, error) { port := startPort nextPort := func() uint32 { defer func() { port++ }() - return uint32(port) + return port } for name := range manifest.OmniEVMs() { diff --git a/e2e/fbproxy/app/middleware.go b/e2e/fbproxy/app/middleware.go index b364a061d..2cfa8c03d 100644 --- a/e2e/fbproxy/app/middleware.go +++ b/e2e/fbproxy/app/middleware.go @@ -3,10 +3,10 @@ package app import ( "context" "encoding/json" - "math/big" "github.com/omni-network/omni/lib/errors" "github.com/omni-network/omni/lib/log" + "github.com/omni-network/omni/lib/umath" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -24,7 +24,7 @@ type txSigner interface { func NewSendTxMiddleware(txsigner txSigner, chainID uint64) Middleware { // sigHelper used to create signature hash and recover tx sender, // not for actual signing which is left to txsigner - sigHelper := types.LatestSignerForChainID(big.NewInt(int64(chainID))) + sigHelper := types.LatestSignerForChainID(umath.NewBigInt(chainID)) return func(ctx context.Context, req JSONRPCMessage) (JSONRPCMessage, error) { if req.Method != "eth_sendTransaction" { diff --git a/e2e/test/attestations_test.go b/e2e/test/attestations_test.go index dc689182f..89bf04312 100644 --- a/e2e/test/attestations_test.go +++ b/e2e/test/attestations_test.go @@ -49,7 +49,7 @@ func TestApprovedAttestations(t *testing.T) { for _, chainVer := range consChain.ChainVersions() { atts, err := fetchAllAtts(ctx, cprov, chainVer, node.StartAt > 0) require.NoError(t, err) - require.NotEmpty(t, len(atts)) + require.NotEmpty(t, atts) } }) } diff --git a/e2e/test/portals_test.go b/e2e/test/portals_test.go index ff87c9858..5057df2fd 100644 --- a/e2e/test/portals_test.go +++ b/e2e/test/portals_test.go @@ -23,7 +23,7 @@ func TestPortalOffsets(t *testing.T) { require.NoError(t, err) // require at least some xmsgs were sent - require.Greater(t, sourceOffset, uint64(0), + require.Positive(t, sourceOffset, "no xmsgs sent from source chain %v to dest chain %v", source.Chain.ID, dest.Chain.ID) diff --git a/e2e/vmcompose/data.go b/e2e/vmcompose/data.go index 88cbe1b46..92138cdf0 100644 --- a/e2e/vmcompose/data.go +++ b/e2e/vmcompose/data.go @@ -16,8 +16,8 @@ import ( var omniEvmRegx = regexp.MustCompile(".*_evm") const ( - evmPort = 8545 - haloPort = 26657 + evmPort = uint32(8545) + haloPort = uint32(26657) relayer = "relayer" ) @@ -76,7 +76,7 @@ func LoadData(path string) (types.InfrastructureData, error) { instances[serviceName] = e2e.InstanceData{ IPAddress: vm.IPAddress, ExtIPAddress: vm.ExtIPAddress, - Port: uint32(port), + Port: port, } } diff --git a/go.mod b/go.mod index 54cd95f20..af00e6362 100644 --- a/go.mod +++ b/go.mod @@ -275,7 +275,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.26.0 // indirect - golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect + golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 golang.org/x/mod v0.20.0 // indirect golang.org/x/net v0.28.0 // indirect golang.org/x/oauth2 v0.22.0 // indirect diff --git a/halo/app/start.go b/halo/app/start.go index b3015c6e7..88a7a5047 100644 --- a/halo/app/start.go +++ b/halo/app/start.go @@ -259,7 +259,7 @@ func makeBaseAppOpts(cfg Config) ([]func(*baseapp.BaseApp), error) { return nil, err } - snapshotOptions := snapshottypes.NewSnapshotOptions(cfg.SnapshotInterval, uint32(cfg.SnapshotKeepRecent)) + snapshotOptions := snapshottypes.NewSnapshotOptions(cfg.SnapshotInterval, cfg.SnapshotKeepRecent) pruneOpts := pruningtypes.NewPruningOptionsFromString(cfg.PruningOption) if cfg.PruningOption == pruningtypes.PruningOptionDefault { diff --git a/halo/attest/keeper/helper.go b/halo/attest/keeper/helper.go index 85d8309c9..f2e1b7436 100644 --- a/halo/attest/keeper/helper.go +++ b/halo/attest/keeper/helper.go @@ -5,6 +5,7 @@ import ( "github.com/omni-network/omni/halo/attest/types" "github.com/omni-network/omni/lib/errors" + "github.com/omni-network/omni/lib/umath" "github.com/omni-network/omni/lib/xchain" ) @@ -19,6 +20,21 @@ func (a *Attestation) IsFuzzy() bool { return xchain.ConfLevel(a.GetConfLevel()).IsFuzzy() } +func statusToDB(status uint32) (Status, error) { + statusInt32, err := umath.ToInt32(status) + if err != nil { + return Status_Unknown, err + } + + resp := Status(statusInt32) + + if resp <= Status_Unknown || resp > Status_Approved { + return 0, errors.New("invalid status") + } + + return resp, nil +} + func AttestationFromDB(att *Attestation, consensusChainID uint64, sigs []*Signature) *types.Attestation { return &types.Attestation{ AttestHeader: &types.AttestHeader{ diff --git a/halo/attest/keeper/keeper.go b/halo/attest/keeper/keeper.go index 9d6af2731..d7dba7ed6 100644 --- a/halo/attest/keeper/keeper.go +++ b/halo/attest/keeper/keeper.go @@ -671,7 +671,7 @@ func (k *Keeper) ExtendVote(ctx sdk.Context, _ *abci.RequestExtendVote) (*abci.R countsByChainVer[vote.AttestHeader.XChainVersion()]++ filtered = append(filtered, vote) - if len(filtered) >= int(k.voteExtLimit) { + if umath.Len(filtered) >= k.voteExtLimit { break } } @@ -749,7 +749,7 @@ func (k *Keeper) VerifyVoteExtension(ctx sdk.Context, req *abci.RequestVerifyVot return respReject, nil } else if !ok { return respAccept, nil - } else if len(votes.Votes) > int(k.voteExtLimit) { + } else if umath.Len(votes.Votes) > k.voteExtLimit { log.Warn(ctx, "Rejecting vote extension exceeding limit", nil, "count", len(votes.Votes), "limit", k.voteExtLimit) return respReject, nil } diff --git a/halo/attest/keeper/query.go b/halo/attest/keeper/query.go index e367f5bab..45f3042be 100644 --- a/halo/attest/keeper/query.go +++ b/halo/attest/keeper/query.go @@ -6,6 +6,7 @@ import ( "github.com/omni-network/omni/halo/attest/types" "github.com/omni-network/omni/lib/errors" "github.com/omni-network/omni/lib/netconf" + "github.com/omni-network/omni/lib/umath" "github.com/omni-network/omni/lib/xchain" sdk "github.com/cosmos/cosmos-sdk/types" @@ -93,9 +94,14 @@ func (k *Keeper) ListAllAttestations(ctx context.Context, req *types.ListAllAtte return nil, status.Error(codes.InvalidArgument, "invalid request") } + s, err := statusToDB(req.Status) + if err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + chainVer := xchain.ChainVersion{ID: req.ChainId, ConfLevel: xchain.ConfLevel(req.ConfLevel)} - atts, err := k.listAllAttestations(ctx, chainVer, Status(req.Status), req.FromOffset) + atts, err := k.listAllAttestations(ctx, chainVer, s, req.FromOffset) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } @@ -113,7 +119,12 @@ func (k *Keeper) WindowCompare(ctx context.Context, req *types.WindowCompareRequ return nil, status.Error(codes.Internal, err.Error()) } - return &types.WindowCompareResponse{Cmp: int32(cmp)}, nil + cmpInt32, err := umath.ToInt32(cmp) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + + return &types.WindowCompareResponse{Cmp: cmpInt32}, nil } func getConsensusChainID(ctx context.Context) (uint64, error) { diff --git a/halo/cmd/flags.go b/halo/cmd/flags.go index 99a8a2dbe..39601d37e 100644 --- a/halo/cmd/flags.go +++ b/halo/cmd/flags.go @@ -23,7 +23,7 @@ func bindRunFlags(cmd *cobra.Command, cfg *halocfg.Config) { flags.StringVar(&cfg.EngineEndpoint, "engine-endpoint", cfg.EngineEndpoint, "An EVM execution client Engine API http endpoint") flags.StringVar(&cfg.EngineJWTFile, "engine-jwt-file", cfg.EngineJWTFile, "The path to the Engine API JWT file") flags.Uint64Var(&cfg.SnapshotInterval, "snapshot-interval", cfg.SnapshotInterval, "State sync snapshot interval") - flags.Uint64Var(&cfg.SnapshotKeepRecent, "snapshot-keep-recent", cfg.SnapshotKeepRecent, "State sync snapshot to keep") + flags.Uint32Var(&cfg.SnapshotKeepRecent, "snapshot-keep-recent", cfg.SnapshotKeepRecent, "State sync snapshot to keep") flags.Uint64Var(&cfg.MinRetainBlocks, "min-retain-blocks", cfg.MinRetainBlocks, "Minimum block height offset during ABCI commit to prune CometBFT blocks") flags.StringVar(&cfg.BackendType, "app-db-backend", cfg.BackendType, "The type of database for application and snapshots databases") flags.StringVar(&cfg.PruningOption, "pruning", cfg.PruningOption, "Pruning strategy (default|nothing|everything)") diff --git a/halo/cmd/testdata/TestCLIReference_rollback.golden b/halo/cmd/testdata/TestCLIReference_rollback.golden index 17143d412..f26dc446c 100644 --- a/halo/cmd/testdata/TestCLIReference_rollback.golden +++ b/halo/cmd/testdata/TestCLIReference_rollback.golden @@ -26,7 +26,7 @@ Flags: --network string Omni network to participate in: mainnet, omega, devnet --pruning string Pruning strategy (default|nothing|everything) (default "default") --snapshot-interval uint State sync snapshot interval (default 1000) - --snapshot-keep-recent uint State sync snapshot to keep (default 2) + --snapshot-keep-recent uint32 State sync snapshot to keep (default 2) --tracing-endpoint string Tracing OTLP endpoint --tracing-headers string Tracing OTLP headers --unsafe-skip-upgrades ints Skip a set of upgrade heights to continue the old binary diff --git a/halo/cmd/testdata/TestCLIReference_run.golden b/halo/cmd/testdata/TestCLIReference_run.golden index bd72d92c5..61e7641d6 100644 --- a/halo/cmd/testdata/TestCLIReference_run.golden +++ b/halo/cmd/testdata/TestCLIReference_run.golden @@ -18,7 +18,7 @@ Flags: --network string Omni network to participate in: mainnet, omega, devnet --pruning string Pruning strategy (default|nothing|everything) (default "default") --snapshot-interval uint State sync snapshot interval (default 1000) - --snapshot-keep-recent uint State sync snapshot to keep (default 2) + --snapshot-keep-recent uint32 State sync snapshot to keep (default 2) --tracing-endpoint string Tracing OTLP endpoint --tracing-headers string Tracing OTLP headers --unsafe-skip-upgrades ints Skip a set of upgrade heights to continue the old binary diff --git a/halo/config/config.go b/halo/config/config.go index 3a91c2a59..4d0154d6a 100644 --- a/halo/config/config.go +++ b/halo/config/config.go @@ -68,7 +68,7 @@ type Config struct { EngineEndpoint string RPCEndpoints xchain.RPCEndpoints SnapshotInterval uint64 // See cosmossdk.io/store/snapshots/types/options.go - SnapshotKeepRecent uint64 // See cosmossdk.io/store/snapshots/types/options.go + SnapshotKeepRecent uint32 // See cosmossdk.io/store/snapshots/types/options.go BackendType string // See cosmos-db/db.go MinRetainBlocks uint64 PruningOption string // See cosmossdk.io/store/pruning/types/options.go diff --git a/halo/evmupgrade/evmupgrade.go b/halo/evmupgrade/evmupgrade.go index 7227e4efc..231717d29 100644 --- a/halo/evmupgrade/evmupgrade.go +++ b/halo/evmupgrade/evmupgrade.go @@ -10,6 +10,7 @@ import ( "github.com/omni-network/omni/lib/errors" "github.com/omni-network/omni/lib/ethclient" "github.com/omni-network/omni/lib/log" + "github.com/omni-network/omni/lib/umath" evmenginetypes "github.com/omni-network/omni/octane/evmengine/types" "github.com/ethereum/go-ethereum" @@ -137,21 +138,21 @@ func (p EventProcessor) deliverCancelUpgrade(ctx context.Context, _ *bindings.Up func (p EventProcessor) deliverPlanUpgrade(ctx context.Context, plan *bindings.UpgradePlanUpgrade) error { log.Info(ctx, "EVM plan upgrade detected", "name", plan.Name, "height", plan.Height) - height := int64(plan.Height) - if height < 0 { - return errors.New("invalid height") + heightInt64, err := umath.ToInt64(plan.Height) + if err != nil { + return err } msg := utypes.MsgSoftwareUpgrade{ Authority: authtypes.NewModuleAddress(ModuleName).String(), Plan: utypes.Plan{ Name: plan.Name, - Height: height, + Height: heightInt64, Info: plan.Info, }, } - _, err := ukeeper.NewMsgServerImpl(p.uKeeper).SoftwareUpgrade(ctx, &msg) + _, err = ukeeper.NewMsgServerImpl(p.uKeeper).SoftwareUpgrade(ctx, &msg) if err != nil { return errors.Wrap(err, "plan software upgrade") } diff --git a/halo/genutil/evm/evm.go b/halo/genutil/evm/evm.go index 06e2dc2fe..67f1c91f3 100644 --- a/halo/genutil/evm/evm.go +++ b/halo/genutil/evm/evm.go @@ -8,6 +8,7 @@ import ( "github.com/omni-network/omni/lib/anvil" "github.com/omni-network/omni/lib/errors" "github.com/omni-network/omni/lib/netconf" + "github.com/omni-network/omni/lib/umath" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" @@ -49,7 +50,7 @@ func MakeGenesis(network netconf.ID) (core.Genesis, error) { // See geth reference: https://github.com/ethereum/go-ethereum/blob/master/params/config.go#L65 func defaultChainConfig(network netconf.ID) *params.ChainConfig { return ¶ms.ChainConfig{ - ChainID: big.NewInt(int64(network.Static().OmniExecutionChainID)), + ChainID: umath.NewBigInt(network.Static().OmniExecutionChainID), HomesteadBlock: big.NewInt(0), EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(0), diff --git a/lib/buildinfo/buildinfo.go b/lib/buildinfo/buildinfo.go index 350014de3..2369ef9d4 100644 --- a/lib/buildinfo/buildinfo.go +++ b/lib/buildinfo/buildinfo.go @@ -57,7 +57,7 @@ func NewVersionCmd() *cobra.Command { _, _ = sb.WriteString("Git Timestamp " + timestamp) _, _ = sb.WriteString("\n") - cmd.Printf(sb.String()) + cmd.Printf(sb.String()) //nolint:govet // Not a problem }, } } diff --git a/lib/cchain/provider/abci.go b/lib/cchain/provider/abci.go index 782087401..7d2668c70 100644 --- a/lib/cchain/provider/abci.go +++ b/lib/cchain/provider/abci.go @@ -427,7 +427,12 @@ func (a rpcAdaptor) Invoke(ctx context.Context, method string, req, resp any, _ queryHeight = v } - r, err := a.abci.ABCIQueryWithOptions(ctx, method, bz, rpcclient.ABCIQueryOptions{Height: int64(queryHeight)}) + queryHeightInt64, err := umath.ToInt64(queryHeight) + if err != nil { + return err + } + + r, err := a.abci.ABCIQueryWithOptions(ctx, method, bz, rpcclient.ABCIQueryOptions{Height: queryHeightInt64}) if err != nil { return errors.Wrap(err, "abci query") } else if !r.Response.IsOK() { diff --git a/lib/ethclient/enginemock.go b/lib/ethclient/enginemock.go index e02b72064..7bf17fed8 100644 --- a/lib/ethclient/enginemock.go +++ b/lib/ethclient/enginemock.go @@ -15,6 +15,7 @@ import ( "github.com/omni-network/omni/lib/k1util" "github.com/omni-network/omni/lib/log" "github.com/omni-network/omni/lib/netconf" + "github.com/omni-network/omni/lib/umath" "github.com/cometbft/cometbft/crypto" @@ -115,8 +116,8 @@ func WithPortalRegister(network netconf.Network) func(*engineMock) { Address: contractAddr, Topics: []common.Hash{ portalRegEvent.ID, - common.BytesToHash(math.U256Bytes(big.NewInt(int64(chain.ID)))), // ChainID - common.BytesToHash(chain.PortalAddress.Bytes()), // Address + common.BytesToHash(math.U256Bytes(umath.NewBigInt(chain.ID))), // ChainID + common.BytesToHash(chain.PortalAddress.Bytes()), // Address }, Data: data, } @@ -203,7 +204,7 @@ func NewEngineMock(opts ...func(mock *engineMock)) (EngineClient, error) { } m := &engineMock{ - fuzzer: NewFuzzer(int64(genesisBlock.Time())), + fuzzer: NewFuzzer(int64(genesisBlock.Time())), //nolint:gosec // Not a problem head: genesisBlock, pendingLogs: make(map[common.Address][]types.Log), payloads: make(map[engine.PayloadID]payloadArgs), @@ -300,7 +301,7 @@ func (m *engineMock) HeaderByType(ctx context.Context, typ HeadType) (*types.Hea return nil, err } - return m.HeaderByNumber(ctx, big.NewInt(int64(number))) + return m.HeaderByNumber(ctx, umath.NewBigInt(number)) } func (m *engineMock) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { @@ -384,7 +385,7 @@ func (m *engineMock) ForkchoiceUpdatedV3(ctx context.Context, update engine.Fork } // Maybe update head - //nolint: nestif // this is a mock it's fine + //nolint:nestif // this is a mock it's fine if m.head.Hash() != update.HeadBlockHash { var found bool for _, args := range m.payloads { @@ -483,7 +484,7 @@ func makePayload(fuzzer *fuzz.Fuzzer, height uint64, timestamp uint64, parentHas // Build a new header var header types.Header fuzzer.Fuzz(&header) - header.Number = big.NewInt(int64(height)) + header.Number = umath.NewBigInt(height) header.Time = timestamp header.ParentHash = parentHash header.MixDigest = randao // this corresponds to Random field in PayloadAttributes diff --git a/lib/fireblocks/jsonhttp.go b/lib/fireblocks/jsonhttp.go index 81a5f708d..f1c4f50bf 100644 --- a/lib/fireblocks/jsonhttp.go +++ b/lib/fireblocks/jsonhttp.go @@ -68,7 +68,7 @@ func (c jsonHTTP) Send(ctx context.Context, uri string, httpMethod string, reque return false, errors.Wrap(err, "read response body") } - if resp.StatusCode/100 != 2 { //nolint:usestdlibvars,nestif // False positive. + if resp.StatusCode/100 != 2 { //nolint:nestif // False positive. if errResponse != nil { // When rate limited, Fireblocks returns http body and not JSON. if resp.StatusCode == http.StatusTooManyRequests { diff --git a/lib/netconf/provider.go b/lib/netconf/provider.go index 89d92e359..16aeb53cf 100644 --- a/lib/netconf/provider.go +++ b/lib/netconf/provider.go @@ -13,6 +13,7 @@ import ( "github.com/omni-network/omni/lib/evmchain" "github.com/omni-network/omni/lib/expbackoff" "github.com/omni-network/omni/lib/log" + "github.com/omni-network/omni/lib/umath" "github.com/omni-network/omni/lib/xchain" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -130,16 +131,19 @@ func containsAll(network Network, expected []string) bool { func networkFromPortals(ctx context.Context, network ID, portals []bindings.PortalRegistryDeployment) (Network, error) { var chains []Chain for _, portal := range portals { + // PortalRegistry guarantees BlockPeriod <= MaxInt64, but we check here to be safe. + periodNanos, err := umath.ToInt64(portal.BlockPeriod) + if err != nil { + return Network{}, err + } + period := time.Duration(periodNanos) * time.Nanosecond + // Ephemeral networks may contain mock portals for testing purposes, just ignore them. - if _, ok := evmchain.MetadataByID(portal.ChainId); !ok && network.IsEphemeral() { + if meta, ok := evmchain.MetadataByID(portal.ChainId); !ok && network.IsEphemeral() { log.Warn(ctx, "Ignoring ephemeral network mock portal", nil, "chain_id", portal.ChainId) continue - } - - // PortalRegistry guarantees BlockPeriod <= int64 max, but we check here to be safe. - blockPeriod := time.Duration(int64(portal.BlockPeriod)) - if blockPeriod < 0 { - return Network{}, errors.New("block period overflow", "period", portal.BlockPeriod) + } else if network != Simnet && ok && meta.BlockPeriod != period { // Sanity check block period + return Network{}, errors.New("invalid portal block period [BUG]", "chain", portal.Name, "got", period, "want", meta.BlockPeriod) // Sanity check } chains = append(chains, Chain{ @@ -147,7 +151,7 @@ func networkFromPortals(ctx context.Context, network ID, portals []bindings.Port Name: portal.Name, PortalAddress: portal.Addr, DeployHeight: portal.DeployHeight, - BlockPeriod: blockPeriod, + BlockPeriod: period, Shards: toShardIDs(portal.Shards), AttestInterval: portal.AttestInterval, }) diff --git a/lib/stream/stream.go b/lib/stream/stream.go index bbc2066ea..3ea82c3da 100644 --- a/lib/stream/stream.go +++ b/lib/stream/stream.go @@ -3,6 +3,7 @@ package stream import ( "context" + "math" "sync" "time" @@ -173,7 +174,7 @@ func startFetchWorkers[E any]( startHeight uint64, ) { for i := uint64(0); i < deps.FetchWorkers; i++ { - go func(workerID int, height uint64) { + go func(workerID uint64, height uint64) { for { // Work function MUST be robust, always returning a non-empty strictly-sequential batch // or nil if the context was canceled. @@ -202,7 +203,7 @@ func startFetchWorkers[E any]( // Calculate next height to fetch height = last + deps.FetchWorkers } - }(int(i), startHeight+i) // Initialize a height to fetch per worker + }(i, startHeight+i) // Initialize a height to fetch per worker } } @@ -215,20 +216,20 @@ type sortingBuffer[E any] struct { mu sync.Mutex buffer map[uint64]workerElem[E] // Worker elements by height - counts map[int]int // Count of elements per worker - signals map[int]chan struct{} // Processes <> Worker comms + counts map[uint64]int // Count of elements per worker + signals map[uint64]chan struct{} // Processes <> Worker comms } -const processorID = -1 +const processorID = math.MaxUint64 func newSortingBuffer[E any]( startHeight uint64, deps Deps[E], callback func(ctx context.Context, elem E) error, ) *sortingBuffer[E] { - signals := make(map[int]chan struct{}) + signals := make(map[uint64]chan struct{}) signals[processorID] = make(chan struct{}, 1) - for i := 0; i < int(deps.FetchWorkers); i++ { + for i := uint64(0); i < deps.FetchWorkers; i++ { signals[i] = make(chan struct{}, 1) } @@ -237,13 +238,13 @@ func newSortingBuffer[E any]( deps: deps, callback: callback, buffer: make(map[uint64]workerElem[E]), - counts: make(map[int]int), + counts: make(map[uint64]int), signals: signals, } } // signal signals the ID to wakeup. -func (m *sortingBuffer[E]) signal(signalID int) { +func (m *sortingBuffer[E]) signal(signalID uint64) { select { case m.signals[signalID] <- struct{}{}: default: @@ -252,7 +253,7 @@ func (m *sortingBuffer[E]) signal(signalID int) { // retryLock repeatedly obtains the lock and calls the callback while it returns false. // It returns once the callback returns true or an error. -func (m *sortingBuffer[E]) retryLock(ctx context.Context, signalID int, fn func(ctx context.Context) (bool, error)) error { +func (m *sortingBuffer[E]) retryLock(ctx context.Context, signalID uint64, fn func(ctx context.Context) (bool, error)) error { timer := time.NewTicker(time.Nanosecond) // Initial timer is instant defer timer.Stop() @@ -278,7 +279,7 @@ func (m *sortingBuffer[E]) retryLock(ctx context.Context, signalID int, fn func( } } -func (m *sortingBuffer[E]) Add(ctx context.Context, workerID int, batch []E) { +func (m *sortingBuffer[E]) Add(ctx context.Context, workerID uint64, batch []E) { _ = m.retryLock(ctx, workerID, func(_ context.Context) (bool, error) { // Wait for any previous batch this worker added to be processed before adding this batch. // This results in backpressure to workers, basically only buffering a single batch per worker. @@ -339,6 +340,6 @@ func (m *sortingBuffer[E]) Process(ctx context.Context) error { // workerElem represents an element processed by a worker. type workerElem[E any] struct { - WorkerID int + WorkerID uint64 E E } diff --git a/lib/tracer/rooted.go b/lib/tracer/rooted.go index d47b410ec..74b47b096 100644 --- a/lib/tracer/rooted.go +++ b/lib/tracer/rooted.go @@ -33,7 +33,7 @@ func StartChainHeight(ctx context.Context, network netconf.ID, chain string, hei ctx, span := tracer.Start(RootedCtx(ctx, traceID), spanName, opts...) span.SetAttributes(attribute.String("chain", chain)) - span.SetAttributes(attribute.Int64("height", int64(height))) + span.SetAttributes(attribute.Int64("height", int64(height))) //nolint:gosec // Not critical return ctx, span } diff --git a/lib/txmgr/config.go b/lib/txmgr/config.go index e7a1e56ec..814119f60 100644 --- a/lib/txmgr/config.go +++ b/lib/txmgr/config.go @@ -8,6 +8,7 @@ import ( "github.com/omni-network/omni/lib/errors" "github.com/omni-network/omni/lib/ethclient" + "github.com/omni-network/omni/lib/umath" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -101,7 +102,7 @@ func (m CLIConfig) Check() error { } func externalSignerFn(external ExternalSigner, address common.Address, chainID uint64) SignerFn { - signer := types.LatestSignerForChainID(big.NewInt(int64(chainID))) + signer := types.LatestSignerForChainID(umath.NewBigInt(chainID)) return func(ctx context.Context, from common.Address, tx *types.Transaction) (*types.Transaction, error) { if address != from { return nil, bind.ErrNotAuthorized @@ -124,7 +125,7 @@ func externalSignerFn(external ExternalSigner, address common.Address, chainID u // privateKeySignerFn returns a SignerFn that signs transactions with the given private key. func privateKeySignerFn(key *ecdsa.PrivateKey, chainID uint64) SignerFn { from := crypto.PubkeyToAddress(key.PublicKey) - signer := types.LatestSignerForChainID(big.NewInt(int64(chainID))) + signer := types.LatestSignerForChainID(umath.NewBigInt(chainID)) return func(_ context.Context, address common.Address, tx *types.Transaction) (*types.Transaction, error) { if address != from { @@ -248,8 +249,6 @@ func newConfig(cfg CLIConfig, signer SignerFn, from common.Address, client ethcl return Config{}, errors.Wrap(err, "invalid min tip cap") } - chainID := big.NewInt(int64(cfg.ChainID)) - return Config{ Backend: client, ResubmissionTimeout: cfg.ResubmissionTimeout, @@ -257,7 +256,7 @@ func newConfig(cfg CLIConfig, signer SignerFn, from common.Address, client ethcl FeeLimitThreshold: feeLimitThreshold, MinBaseFee: minBaseFee, MinTipCap: minTipCap, - ChainID: chainID, + ChainID: umath.NewBigInt(cfg.ChainID), TxSendTimeout: cfg.TxSendTimeout, TxNotInMempoolTimeout: cfg.TxNotInMempoolTimeout, NetworkTimeout: cfg.NetworkTimeout, diff --git a/lib/txmgr/txmgr.go b/lib/txmgr/txmgr.go index 65e3b2ebc..93fd5df64 100644 --- a/lib/txmgr/txmgr.go +++ b/lib/txmgr/txmgr.go @@ -116,14 +116,14 @@ func (m *simple) From() common.Address { // txFields returns a logger with the transaction hash and nonce fields set. func txFields(tx *types.Transaction, logGas bool) []any { fields := []any{ - slog.Int64("nonce", int64(tx.Nonce())), + slog.Uint64("nonce", tx.Nonce()), slog.String("tx", tx.Hash().String()), } if logGas { fields = append(fields, slog.String("gas_tip_cap", tx.GasTipCap().String()), slog.String("gas_fee_cap", tx.GasFeeCap().String()), - slog.Int64("gas_limit", int64(tx.Gas())), + slog.Uint64("gas_limit", tx.Gas()), ) } @@ -618,7 +618,7 @@ func (m *simple) suggestGasPriceCaps(ctx context.Context) (*big.Int, *big.Int, e // if FeeLimitThreshold is specified in config, any increase which stays under the threshold are allowed. func (m *simple) checkLimits(tip, baseFee, bumpedTip, bumpedFee *big.Int) error { threshold := m.cfg.FeeLimitThreshold - limit := big.NewInt(int64(m.cfg.FeeLimitMultiplier)) + limit := umath.NewBigInt(m.cfg.FeeLimitMultiplier) maxTip := new(big.Int).Mul(tip, limit) maxFee := calcGasFeeCap(new(big.Int).Mul(baseFee, limit), maxTip) var errs error diff --git a/lib/umath/umath.go b/lib/umath/umath.go index 7493debd1..fea7fa8a0 100644 --- a/lib/umath/umath.go +++ b/lib/umath/umath.go @@ -1,6 +1,17 @@ // Package umath provides some useful unsigned math functions to prevent underflows. +// It also provides some type conversion functions to convert between different +// integer types to prevent underflows and overflows or overflows. package umath +import ( + "math" + "math/big" + + "github.com/omni-network/omni/lib/errors" + + "golang.org/x/exp/constraints" +) + // Subtract returns a - b and true if a >= b, otherwise 0 and false. func Subtract(a, b uint64) (uint64, bool) { if a < b { @@ -16,3 +27,66 @@ func SubtractOrZero(a, b uint64) uint64 { resp, _ := Subtract(a, b) return resp } + +// NewBigInt return a big.Int version of the provided uint64. +// This is a convenience function to avoid gosec complaining about big.NewInt(int64(i))). +func NewBigInt(i uint64) *big.Int { + return new(big.Int).SetUint64(i) +} + +// Len returns the length of the slice as a uint64. +// This convenience function to avoid gosec complaining about uint64(len(slice)). +func Len[T any](slice []T) uint64 { + l := len(slice) + if l < 0 { + panic("impossible") + } + + return uint64(l) +} + +// ToUint64 returns i as an uint64 or an error if it cannot be represented as such. +func ToUint64[N constraints.Integer](i N) (uint64, error) { + if i < 0 { + return 0, errors.New("underflow") + } + + return uint64(i), nil +} + +// ToInt64 returns i as an int64 or an error if it cannot be represented as such. +func ToInt64[N constraints.Integer](n N) (int64, error) { + // All negative int values are valid int64 + if n < 0 { + return int64(n), nil + } + + if uint64(n) > math.MaxInt64 { + return 0, errors.New("overflow") + } + + return int64(n), nil +} + +// ToUint32 returns i as an uint32 or an error if it cannot be represented as such. +func ToUint32[N constraints.Integer](i N) (uint32, error) { + if i < 0 { + return 0, errors.New("underflow") + } else if uint64(i) > math.MaxUint32 { + return 0, errors.New("overflow") + } + + return uint32(i), nil +} + +// ToInt32 returns i as an int32 or an error if it cannot be represented as such. +func ToInt32[N constraints.Integer](i N) (int32, error) { + // Using float64 for int32 is fine since rounding not a problem. + if float64(i) > math.MaxInt32 { + return 0, errors.New("overflow") + } else if float64(i) < math.MinInt32 { + return 0, errors.New("underflow") + } + + return int32(i), nil +} diff --git a/lib/umath/umath_test.go b/lib/umath/umath_test.go new file mode 100644 index 000000000..bae2b17aa --- /dev/null +++ b/lib/umath/umath_test.go @@ -0,0 +1,91 @@ +package umath_test + +import ( + "fmt" + "math" + "testing" + + "github.com/omni-network/omni/lib/umath" + + "github.com/stretchr/testify/require" +) + +func TestUintTo(t *testing.T) { + t.Parallel() + tests := []struct { + i uint64 + okInt64 bool + okUint64 bool + okInt32 bool + okUint32 bool + }{ + {math.MaxUint64, false, true, false, false}, + {math.MaxInt64 + 1, false, true, false, false}, + {math.MaxInt64, true, true, false, false}, + {math.MaxUint32 + 1, true, true, false, false}, + {math.MaxUint32, true, true, false, true}, + {math.MaxInt32 + 1, true, true, false, true}, + {math.MaxInt32, true, true, true, true}, + {1, true, true, true, true}, + {0, true, true, true, true}, + } + + for _, test := range tests { + t.Run(fmt.Sprint(test.i), func(t *testing.T) { + t.Parallel() + if _, err := umath.ToInt64(test.i); (err == nil) != test.okInt64 { + require.Fail(t, "ToInt64", "unexpected result: %v", err) + } + if _, err := umath.ToInt32(test.i); (err == nil) != test.okInt32 { + require.Fail(t, "ToInt32", "unexpected result: %v", err) + } + if _, err := umath.ToUint64(test.i); (err == nil) != test.okUint64 { + require.Fail(t, "ToUint64", "unexpected result: %v", err) + } + if _, err := umath.ToUint32(test.i); (err == nil) != test.okUint32 { + require.Fail(t, "ToUint32", "unexpected result: %v", err) + } + }) + } +} + +func TestIntTo(t *testing.T) { + t.Parallel() + tests := []struct { + i int64 + okInt64 bool + okUint64 bool + okInt32 bool + okUint32 bool + }{ + {math.MaxInt64, true, true, false, false}, + {math.MaxUint32 + 1, true, true, false, false}, + {math.MaxUint32, true, true, false, true}, + {math.MaxInt32 + 1, true, true, false, true}, + {math.MaxInt32, true, true, true, true}, + {1, true, true, true, true}, + {0, true, true, true, true}, + {-1, true, false, true, false}, + {math.MinInt32, true, false, true, false}, + {math.MinInt32 - 1, true, false, false, false}, + {math.MinInt64, true, false, false, false}, + } + + for _, test := range tests { + t.Run(fmt.Sprint(test.i), func(t *testing.T) { + t.Parallel() + if _, err := umath.ToInt64(test.i); (err == nil) != test.okInt64 { + require.Fail(t, "ToInt64", "unexpected result: %v", err) + } + if _, err := umath.ToInt32(test.i); (err == nil) != test.okInt32 { + require.Fail(t, "ToInt32", "unexpected result: %v", err) + } + if _, err := umath.ToUint64(test.i); (err == nil) != test.okUint64 { + require.Fail(t, "ToUint64", "unexpected result: %v", err) + } + if _, err := umath.ToUint32(test.i); (err == nil) != test.okUint32 { + require.Fail(t, "ToUint32", "unexpected result: %v", err) + } + }) + } +} diff --git a/lib/xchain/provider/fetch.go b/lib/xchain/provider/fetch.go index dbe63275c..c0618b56e 100644 --- a/lib/xchain/provider/fetch.go +++ b/lib/xchain/provider/fetch.go @@ -2,7 +2,6 @@ package provider import ( "context" - "math/big" "time" "github.com/omni-network/omni/contracts/bindings" @@ -10,6 +9,7 @@ import ( "github.com/omni-network/omni/lib/errors" "github.com/omni-network/omni/lib/ethclient" "github.com/omni-network/omni/lib/tracer" + "github.com/omni-network/omni/lib/umath" "github.com/omni-network/omni/lib/xchain" "github.com/ethereum/go-ethereum" @@ -91,7 +91,7 @@ func (p *Provider) GetEmittedCursor(ctx context.Context, ref xchain.EmitRef, str opts := &bind.CallOpts{Context: ctx} if ref.Height != nil { - opts.BlockNumber = big.NewInt(int64(*ref.Height)) + opts.BlockNumber = umath.NewBigInt(*ref.Height) } else if head, ok := headTypeFromConfLevel(*ref.ConfLevel); !ok { return xchain.EmitCursor{}, false, errors.New("invalid conf level") } else { @@ -138,7 +138,7 @@ func (p *Provider) GetSubmittedCursor(ctx context.Context, stream xchain.StreamI return xchain.SubmitCursor{}, false, err } - callOpts := &bind.CallOpts{Context: ctx, BlockNumber: big.NewInt(int64(height))} + callOpts := &bind.CallOpts{Context: ctx, BlockNumber: umath.NewBigInt(height)} msgOffset, err := caller.InXMsgOffset(callOpts, stream.SourceChainID, uint64(stream.ShardID)) if err != nil { @@ -215,7 +215,7 @@ func (p *Provider) GetBlock(ctx context.Context, req xchain.ProviderRequest) (xc // Fetch the header if we didn't find it in the cache if header == nil { - header, err = ethCl.HeaderByNumber(ctx, big.NewInt(int64(req.Height))) + header, err = ethCl.HeaderByNumber(ctx, umath.NewBigInt(req.Height)) if err != nil { return xchain.Block{}, false, errors.Wrap(err, "header by number") } @@ -240,6 +240,11 @@ func (p *Provider) GetBlock(ctx context.Context, req xchain.ProviderRequest) (xc return xchain.Block{}, false, errors.Wrap(err, "wait") } + timeSecs, err := umath.ToInt64(header.Time) + if err != nil { + return xchain.Block{}, false, err + } + return xchain.Block{ BlockHeader: xchain.BlockHeader{ ChainID: req.ChainID, @@ -249,7 +254,7 @@ func (p *Provider) GetBlock(ctx context.Context, req xchain.ProviderRequest) (xc Msgs: msgs, Receipts: receipts, ParentHash: header.ParentHash, - Timestamp: time.Unix(int64(header.Time), 0), + Timestamp: time.Unix(timeSecs, 0), }, true, nil } diff --git a/monitor/app/sync.go b/monitor/app/sync.go index dcaac4aea..8c88bc32c 100644 --- a/monitor/app/sync.go +++ b/monitor/app/sync.go @@ -8,6 +8,7 @@ import ( "github.com/omni-network/omni/lib/ethclient" "github.com/omni-network/omni/lib/log" "github.com/omni-network/omni/lib/netconf" + "github.com/omni-network/omni/lib/umath" ) // startMonitoringSyncDiff starts a goroutine per chain that periodically calculates the rpc-sync-diff @@ -38,12 +39,12 @@ func startMonitoringSyncDiff( } // calcMaxDiff returns the maximum difference between the provided heights. -func calcMaxDiff(heights []int64) int64 { +func calcMaxDiff(heights []uint64) uint64 { if len(heights) == 0 { return 0 } - minimum, maximum := int64(math.MaxInt64), int64(math.MinInt64) + minimum, maximum := uint64(0), uint64(math.MaxUint64) for _, height := range heights { if minimum > height { minimum = height @@ -53,11 +54,11 @@ func calcMaxDiff(heights []int64) int64 { } } - return maximum - minimum + return umath.SubtractOrZero(maximum, minimum) } // concurrentLatestHeights returns the non-zero latest heights returned from N concurrent queries. -func concurrentLatestHeights(ctx context.Context, ethCl ethclient.Client, n int) []int64 { +func concurrentLatestHeights(ctx context.Context, ethCl ethclient.Client, n int) []uint64 { collect := make(chan uint64, n) for i := 0; i < n; i++ { go func() { @@ -69,11 +70,11 @@ func concurrentLatestHeights(ctx context.Context, ethCl ethclient.Client, n int) }() } - var resp []int64 + var resp []uint64 for i := 0; i < n; i++ { height := <-collect if height > 0 { - resp = append(resp, int64(height)) + resp = append(resp, height) } } diff --git a/monitor/xfeemngr/gasprice/mock.go b/monitor/xfeemngr/gasprice/mock.go index 2f74ce21a..3a1914458 100644 --- a/monitor/xfeemngr/gasprice/mock.go +++ b/monitor/xfeemngr/gasprice/mock.go @@ -5,6 +5,8 @@ import ( "math/big" "sync" + "github.com/omni-network/omni/lib/umath" + "github.com/ethereum/go-ethereum" ) @@ -26,7 +28,7 @@ func (m *MockPricer) SuggestGasPrice(_ context.Context) (*big.Int, error) { m.mu.RLock() defer m.mu.RUnlock() - return big.NewInt(int64(m.price)), nil + return umath.NewBigInt(m.price), nil } func (m *MockPricer) SetPrice(price uint64) { diff --git a/relayer/app/sender.go b/relayer/app/sender.go index 67f1cb4a8..36ea26e4b 100644 --- a/relayer/app/sender.go +++ b/relayer/app/sender.go @@ -104,7 +104,7 @@ func (s Sender) SendTransaction(ctx context.Context, sub xchain.Submission) erro ctx = log.WithCtx(ctx, reqAttrs...) log.Debug(ctx, "Received submission", - "block_offset", sub.AttHeader.ChainVersion, + "attest_offset", sub.AttHeader.AttestOffset, "start_msg_offset", startOffset, "msgs", len(sub.Msgs), ) diff --git a/relayer/app/worker.go b/relayer/app/worker.go index 0924f03b7..c8ecaed6a 100644 --- a/relayer/app/worker.go +++ b/relayer/app/worker.go @@ -77,7 +77,7 @@ func (w *Worker) runOnce(ctx context.Context) error { for _, cursor := range cursors { log.Info(ctx, "Worker fetched submitted cursor", "stream", w.network.StreamName(cursor.StreamID), - "block_offset", cursor.AttestOffset, + "attest_offset", cursor.AttestOffset, "msg_offset", cursor.MsgOffset, ) }