From 6f92bbf69f309d0001a5803794638cde640ea36a Mon Sep 17 00:00:00 2001 From: Alfonso Acosta Date: Thu, 20 Jun 2024 13:18:00 +0200 Subject: [PATCH] Enable Golangci-lint (#224) --- .github/workflows/codeql.yml | 36 +-- .../{golangci-lint.yml => golang.yml} | 14 +- .github/workflows/required_status_check.yml | 2 +- .github/workflows/rust.yml | 2 +- .github/workflows/soroban-rpc.yml | 14 +- .golangci.yml | 205 +++++++++--------- Makefile | 4 +- .../internal/config/config_option.go | 9 +- cmd/soroban-rpc/internal/config/options.go | 1 + cmd/soroban-rpc/internal/config/parse.go | 10 +- cmd/soroban-rpc/internal/daemon/daemon.go | 12 +- .../internal/daemon/interfaces/interfaces.go | 3 +- .../internal/daemon/interfaces/noOpDaemon.go | 1 + cmd/soroban-rpc/internal/daemon/metrics.go | 8 +- cmd/soroban-rpc/internal/db/db.go | 2 +- cmd/soroban-rpc/internal/db/ledgerentry.go | 2 +- cmd/soroban-rpc/internal/db/migration.go | 6 +- cmd/soroban-rpc/internal/db/mocks.go | 8 +- cmd/soroban-rpc/internal/db/transaction.go | 6 +- cmd/soroban-rpc/internal/events/events.go | 5 +- .../internal/feewindow/feewindow.go | 2 +- .../internal/ingest/ledgerentry.go | 1 + cmd/soroban-rpc/internal/ingest/service.go | 4 +- .../internal/ingest/service_test.go | 3 +- .../integrationtest/infrastructure/test.go | 10 +- cmd/soroban-rpc/internal/jsonrpc.go | 3 +- .../ledgerbucketwindow/ledgerbucketwindow.go | 7 +- .../internal/methods/get_events.go | 14 +- .../internal/methods/get_fee_stats.go | 2 +- .../internal/methods/get_ledger_entries.go | 1 + .../internal/methods/get_ledger_entry.go | 4 +- .../internal/methods/get_transaction.go | 1 + .../internal/methods/get_transactions.go | 3 +- .../internal/methods/get_version_info.go | 15 +- cmd/soroban-rpc/internal/methods/health.go | 3 +- .../internal/methods/send_transaction.go | 1 + .../internal/methods/simulate_transaction.go | 6 +- cmd/soroban-rpc/internal/network/backlogQ.go | 5 +- .../internal/network/backlogQ_test.go | 20 +- .../network/requestdurationlimiter.go | 24 +- .../network/requestdurationlimiter_test.go | 4 +- cmd/soroban-rpc/internal/preflight/pool.go | 1 + .../internal/preflight/preflight.go | 50 +++-- cmd/soroban-rpc/internal/util/panicgroup.go | 5 +- cmd/soroban-rpc/main.go | 4 +- 45 files changed, 299 insertions(+), 244 deletions(-) rename .github/workflows/{golangci-lint.yml => golang.yml} (76%) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index d48e5f05..54dbaa1f 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -21,21 +21,27 @@ jobs: fail-fast: false matrix: include: - - language: go - build-mode: autobuild - + - language: go + build-mode: autobuild + steps: - - name: Checkout repository - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v4 + - uses: ./.github/actions/setup-go + with: + go-version: 1.22 + - run: rustup update + - uses: stellar/actions/rust-cache@main + - run: make build-libpreflight - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: ${{ matrix.language }} - build-mode: ${{ matrix.build-mode }} + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 - with: - category: "/language:${{matrix.language}}" + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golang.yml similarity index 76% rename from .github/workflows/golangci-lint.yml rename to .github/workflows/golang.yml index 2a3dbae1..a9726b9e 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golang.yml @@ -1,28 +1,31 @@ -name: Linters +name: Go on: push: - branches: - - main + branches: [ main, release/** ] pull_request: permissions: contents: read # Optional: allow read access to pull request. Use with `only-new-issues` option. pull-requests: read + # Optional: allow write access to checks to allow the action to annotate code in the PR. + checks: write jobs: - golangci: + golangci-lint: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # version v3.0.2 with: fetch-depth: 0 # required for new-from-rev option in .golangci.yml + - name: Setup GO uses: actions/setup-go@268d8c0ca0432bb2cf416faae41297df9d262d7f # version v3.3.0 with: go-version: '>=1.22.1' + - uses: stellar/actions/rust-cache@main - name: Build libpreflight run: | rustup update @@ -31,8 +34,7 @@ jobs: - name: Run golangci-lint uses: golangci/golangci-lint-action@a4f60bb28d35aeee14e6880718e0c85ff1882e64 # version v6.0.1 with: - version: v1.52.2 # this is the golangci-lint version - args: --issues-exit-code=0 # exit without errors for now - won't fail the build + version: v1.59.1 # this is the golangci-lint version github-token: ${{ secrets.GITHUB_TOKEN }} only-new-issues: true diff --git a/.github/workflows/required_status_check.yml b/.github/workflows/required_status_check.yml index 9406aed9..0362afb3 100644 --- a/.github/workflows/required_status_check.yml +++ b/.github/workflows/required_status_check.yml @@ -13,6 +13,6 @@ jobs: with: filter-workflow-names: | Dependency sanity checker* - Linters* + Go* Rust* Soroban RPC* diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 87c5afe8..6f9dd3fa 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: stellar/actions/rust-cache@main - run: rustup update + - uses: stellar/actions/rust-cache@main - run: make rust-check - run: make rust-test diff --git a/.github/workflows/soroban-rpc.yml b/.github/workflows/soroban-rpc.yml index 03d6c336..e9122e82 100644 --- a/.github/workflows/soroban-rpc.yml +++ b/.github/workflows/soroban-rpc.yml @@ -29,6 +29,7 @@ jobs: with: go-version: ${{ matrix.go }} - run: rustup update + - uses: stellar/actions/rust-cache@main - run: make build-libpreflight - run: go test -race -cover -timeout 25m -v ./cmd/soroban-rpc/... @@ -81,9 +82,8 @@ jobs: - run: | rustup target add ${{ matrix.rust_target }} rustup update - - - name: Build libpreflight - run: make build-libpreflight + - uses: stellar/actions/rust-cache@main + - run: make build-libpreflight env: CARGO_BUILD_TARGET: ${{ matrix.rust_target }} @@ -132,8 +132,6 @@ jobs: docker pull "$PROTOCOL_${{ matrix.protocol-version }}_CORE_DOCKER_IMG" echo SOROBAN_RPC_INTEGRATION_TESTS_DOCKER_IMG="$PROTOCOL_${{ matrix.protocol-version }}_CORE_DOCKER_IMG" >> $GITHUB_ENV - - uses: stellar/actions/rust-cache@main - - name: Install Captive Core shell: bash run: | @@ -176,10 +174,8 @@ jobs: docker-compose version - run: rustup update - - - name: Build libpreflight - shell: bash - run: make build-libpreflight + - uses: stellar/actions/rust-cache@main + - run: make build-libpreflight - name: Run Soroban RPC Integration Tests run: | diff --git a/.golangci.yml b/.golangci.yml index 28fbe1f9..aca3ea8a 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,122 +1,123 @@ linters-settings: - depguard: dupl: threshold: 100 + funlen: lines: 100 statements: 50 - goconst: - min-len: 2 - min-occurrences: 3 - gocritic: - enabled-tags: - - diagnostic - - experimental - - opinionated - - performance - - style - disabled-checks: - - dupImport # https://github.com/go-critic/go-critic/issues/845 - - ifElseChain - - octalLiteral - - whyNoLint - gocyclo: - min-complexity: 15 - goimports: - local-prefixes: github.com/golangci/golangci-lint - gomnd: - # don't include the "operation" and "assign" - checks: - - argument - - case - - condition - - return - ignored-numbers: - - '0' - - '1' - - '2' - - '3' - ignored-functions: - - strings.SplitN - govet: - check-shadowing: true - settings: - printf: - funcs: - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf - lll: - line-length: 140 misspell: locale: US - nolintlint: - allow-unused: false # report any unused nolint directives - require-explanation: false # don't require an explanation for nolint directives - require-specific: false # don't require nolint directives to be specific about which linter is being skipped + + gci: + # Section configuration to compare against. + # Section names are case-insensitive and may contain parameters in (). + # The default order of sections is `standard > default > custom > blank > dot > alias > localmodule`, + # If `custom-order` is `true`, it follows the order of `sections` option. + # Default: ["standard", "default"] + sections: + - standard # Standard section: captures all standard packages. + - default # Default section: contains all imports that could not be matched to another section type. + - prefix(github.com/stellar/) # Custom section: groups all imports with the specified Prefix. + - localmodule # Local module section: contains all local packages. This section is not present unless explicitly enabled. + skip-generated: false + # Enable custom order of sections. + # If `true`, make the section order the same as the order of `sections`. + # Default: false + custom-order: true + + dogsled: + # Checks assignments with too many blank identifiers. + # Default: 2 + max-blank-identifiers: 3 + + cyclop: + # The maximal code complexity to report. + # Default: 10 + max-complexity: 15 + + wrapcheck: + # An array of strings that specify substrings of signatures to ignore. + # If this set, it will override the default set of ignored signatures. + # See https://github.com/tomarrell/wrapcheck#configuration for more information. + # Default: [".Errorf(", "errors.New(", "errors.Unwrap(", "errors.Join(", ".Wrap(", ".Wrapf(", ".WithMessage(", ".WithMessagef(", ".WithStack("] + ignoreSigs: + - .Errorf( + - errors.New( + - errors.Unwrap( + - errors.Join( + - .Wrap( + - .Wrapf( + - .WithMessage( + - .WithMessagef( + - .WithStack( + # An array of strings that specify regular expressions of signatures to ignore. + # Default: [] + ignoreSigRegexps: + - \.New.*Error\( + # An array of strings that specify globs of packages to ignore. + # Default: [] + ignorePackageGlobs: + - encoding/* + - github.com/pkg/* + - github.com/stellar/* + # An array of strings that specify regular expressions of interfaces to ignore. + # Default: [] + ignoreInterfaceRegexps: + - ^(?i)c(?-i)ach(ing|e) + + testifylint: + enable-all: true + disable: + # TODO: try to enable it + - go-require + + forbidigo: + # Forbid the following identifiers (list of regexp). + # Default: ["^(fmt\\.Print(|f|ln)|print|println)$"] + forbid: + - p: "^(fmt\\.Print(|f|ln)|print|println)$" + msg: Do not commit debug print statements (in tests use t.Log()). + - p: "^.*$" + pkg: "^github.com/stellar/go/support/errors$" + msg: Do not use stellar/go/support/errors, use the standard 'errors' package and fmt.Errorf(). + exclude-godoc-examples: false + analyze-types: true linters: - disable-all: true - enable: - - bodyclose + enable-all: true + disable: + - gomnd + - execinquery - depguard - - dogsled - - dupl - - errcheck - - exportloopref - #- funlen - - gochecknoinits - - goconst - #- gocritic - #- gocyclo - - gofmt - - goimports - #- gomnd - - goprintffuncname - - gosec - - gosimple - - govet - - ineffassign - #- lll - - misspell - - nakedret - - noctx - - nolintlint - - staticcheck - - stylecheck - - typecheck - - unconvert - - unparam - - unused - - whitespace - - # don't enable: - # - asciicheck - # - scopelint - # - gochecknoglobals - # - gocognit - # - godot - # - godox - # - goerr113 - # - interfacer - # - maligned - # - nestif - # - prealloc - # - testpackage - # - revive - # - wsl + - nlreturn + - godox + # exhaustruct: enforcing exhaustive fields is useful in some cases, but there are + # too many legitimate default field values in Go + - exhaustruct + # err113: Enforcing errors.Is() is useful but cannot be enabled in isolation + - err113 + - thelper + - wsl + - wrapcheck + - testpackage + # TODO: I didn't manage to make it accept short parameter names + - varnamelen + # TODO: consider enabling it later on + - ireturn + - godot + presets: [ ] + fast: false issues: # Excluding configuration per-path, per-linter, per-text and per-source exclude-rules: - path: _test\.go linters: - - govet + - gosec + - path: cmd/soroban-rpc/internal/integrationtest/infrastructure/ + linters: + - gosec run: - timeout: 5m - skip-dirs: - - docs - - vendor + timeout: 10m diff --git a/Makefile b/Makefile index c9e37996..0e0b713e 100644 --- a/Makefile +++ b/Makefile @@ -81,8 +81,8 @@ clean: build-soroban-rpc: build-libpreflight go build -ldflags="${GOLDFLAGS}" ${MACOS_MIN_VER} -o soroban-rpc -trimpath -v ./cmd/soroban-rpc -go-check-changes: - golangci-lint run ./... --new-from-rev $$(git rev-parse HEAD) +go-check-branch: + golangci-lint run ./... --new-from-rev $$(git rev-parse origin/main) go-check: golangci-lint run ./... diff --git a/cmd/soroban-rpc/internal/config/config_option.go b/cmd/soroban-rpc/internal/config/config_option.go index 3c8ca87a..ffbdc936 100644 --- a/cmd/soroban-rpc/internal/config/config_option.go +++ b/cmd/soroban-rpc/internal/config/config_option.go @@ -1,13 +1,14 @@ package config import ( + "errors" "fmt" "reflect" "strconv" "time" "github.com/spf13/pflag" - "github.com/stellar/go/support/errors" + "github.com/stellar/go/support/strutils" ) @@ -28,7 +29,7 @@ func (options ConfigOptions) Validate() error { missingOptions = append(missingOptions, missingOption) continue } - return errors.Wrap(err, fmt.Sprintf("Invalid config value for %s", option.Name)) + return errors.New("Invalid config value for " + option.Name) } } if len(missingOptions) > 0 { @@ -95,11 +96,11 @@ func (o *ConfigOption) setValue(i interface{}) (err error) { return } - err = errors.Errorf("config option setting error ('%s') %v", o.Name, recoverRes) + err = fmt.Errorf("config option setting error ('%s') %v", o.Name, recoverRes) } }() parser := func(option *ConfigOption, i interface{}) error { - return errors.Errorf("no parser for flag %s", o.Name) + return fmt.Errorf("no parser for flag %s", o.Name) } switch o.ConfigKey.(type) { case *bool: diff --git a/cmd/soroban-rpc/internal/config/options.go b/cmd/soroban-rpc/internal/config/options.go index 50f0321b..f417a7ee 100644 --- a/cmd/soroban-rpc/internal/config/options.go +++ b/cmd/soroban-rpc/internal/config/options.go @@ -1,3 +1,4 @@ +//nolint:mnd // lots of magic constants due to default values package config import ( diff --git a/cmd/soroban-rpc/internal/config/parse.go b/cmd/soroban-rpc/internal/config/parse.go index 00d93a17..6001f5d7 100644 --- a/cmd/soroban-rpc/internal/config/parse.go +++ b/cmd/soroban-rpc/internal/config/parse.go @@ -16,16 +16,16 @@ func parseBool(option *ConfigOption, i interface{}) error { case nil: return nil case bool: + //nolint:forcetypeassert *option.ConfigKey.(*bool) = v case string: lower := strings.ToLower(v) - if lower == "true" { - *option.ConfigKey.(*bool) = true - } else if lower == "false" { - *option.ConfigKey.(*bool) = false - } else { + b, err := strconv.ParseBool(lower) + if err != nil { return fmt.Errorf("invalid boolean value %s: %s", option.Name, v) } + //nolint:forcetypeassert + *option.ConfigKey.(*bool) = b default: return fmt.Errorf("could not parse boolean %s: %v", option.Name, i) } diff --git a/cmd/soroban-rpc/internal/daemon/daemon.go b/cmd/soroban-rpc/internal/daemon/daemon.go index da56f70e..bf55fa4a 100644 --- a/cmd/soroban-rpc/internal/daemon/daemon.go +++ b/cmd/soroban-rpc/internal/daemon/daemon.go @@ -5,7 +5,7 @@ import ( "errors" "net" "net/http" - "net/http/pprof" //nolint:gosec + "net/http/pprof" "os" "os/signal" runtimePprof "runtime/pprof" @@ -15,6 +15,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/stellar/go/clients/stellarcore" "github.com/stellar/go/historyarchive" "github.com/stellar/go/ingest/ledgerbackend" @@ -66,9 +67,11 @@ func (d *Daemon) GetDB() *db.DB { } func (d *Daemon) GetEndpointAddrs() (net.TCPAddr, *net.TCPAddr) { - var addr = d.listener.Addr().(*net.TCPAddr) + //nolint:forcetypeassert + addr := d.listener.Addr().(*net.TCPAddr) var adminAddr *net.TCPAddr if d.adminListener != nil { + //nolint:forcetypeassert adminAddr = d.adminListener.Addr().(*net.TCPAddr) } return *addr, adminAddr @@ -142,7 +145,6 @@ func newCaptiveCore(cfg *config.Config, logger *supportlog.Entry) (*ledgerbacken UseDB: true, } return ledgerbackend.NewCaptive(captiveConfig) - } func MustNew(cfg *config.Config, logger *supportlog.Entry) *Daemon { @@ -173,10 +175,10 @@ func MustNew(cfg *config.Config, logger *supportlog.Entry) *Daemon { CheckpointFrequency: cfg.CheckpointFrequency, ConnectOptions: storage.ConnectOptions{ Context: context.Background(), - UserAgent: cfg.HistoryArchiveUserAgent}, + UserAgent: cfg.HistoryArchiveUserAgent, + }, }, ) - if err != nil { logger.WithError(err).Fatal("could not connect to history archive") } diff --git a/cmd/soroban-rpc/internal/daemon/interfaces/interfaces.go b/cmd/soroban-rpc/internal/daemon/interfaces/interfaces.go index 529ecdef..b97cb376 100644 --- a/cmd/soroban-rpc/internal/daemon/interfaces/interfaces.go +++ b/cmd/soroban-rpc/internal/daemon/interfaces/interfaces.go @@ -4,6 +4,7 @@ import ( "context" "github.com/prometheus/client_golang/prometheus" + proto "github.com/stellar/go/protocols/stellarcore" ) @@ -18,5 +19,5 @@ type Daemon interface { type CoreClient interface { Info(ctx context.Context) (*proto.InfoResponse, error) - SubmitTransaction(context.Context, string) (*proto.TXResponse, error) + SubmitTransaction(ctx context.Context, txBase64 string) (*proto.TXResponse, error) } diff --git a/cmd/soroban-rpc/internal/daemon/interfaces/noOpDaemon.go b/cmd/soroban-rpc/internal/daemon/interfaces/noOpDaemon.go index 78e6cdbf..79a63971 100644 --- a/cmd/soroban-rpc/internal/daemon/interfaces/noOpDaemon.go +++ b/cmd/soroban-rpc/internal/daemon/interfaces/noOpDaemon.go @@ -4,6 +4,7 @@ import ( "context" "github.com/prometheus/client_golang/prometheus" + proto "github.com/stellar/go/protocols/stellarcore" ) diff --git a/cmd/soroban-rpc/internal/daemon/metrics.go b/cmd/soroban-rpc/internal/daemon/metrics.go index 8d0a1820..2e409cf4 100644 --- a/cmd/soroban-rpc/internal/daemon/metrics.go +++ b/cmd/soroban-rpc/internal/daemon/metrics.go @@ -2,13 +2,15 @@ package daemon import ( "context" - supportlog "github.com/stellar/go/support/log" "runtime" "time" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/collectors" + "github.com/stellar/go/clients/stellarcore" proto "github.com/stellar/go/protocols/stellarcore" + supportlog "github.com/stellar/go/support/log" "github.com/stellar/go/support/logmetrics" "github.com/stellar/go/xdr" @@ -36,8 +38,8 @@ func (d *Daemon) registerMetrics() { "goversion": runtime.Version(), }).Inc() - d.metricsRegistry.MustRegister(prometheus.NewGoCollector()) - d.metricsRegistry.MustRegister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{})) + d.metricsRegistry.MustRegister(collectors.NewGoCollector()) + d.metricsRegistry.MustRegister(collectors.NewProcessCollector(collectors.ProcessCollectorOpts{})) d.metricsRegistry.MustRegister(buildInfoGauge) } diff --git a/cmd/soroban-rpc/internal/db/db.go b/cmd/soroban-rpc/internal/db/db.go index a3d54a6f..966f8cd8 100644 --- a/cmd/soroban-rpc/internal/db/db.go +++ b/cmd/soroban-rpc/internal/db/db.go @@ -294,7 +294,7 @@ func (w writeTx) Commit(ledgerSeq uint32) error { } _, err := sq.Replace(metaTableName). - Values(latestLedgerSequenceMetaKey, fmt.Sprintf("%d", ledgerSeq)). + Values(latestLedgerSequenceMetaKey, strconv.FormatUint(uint64(ledgerSeq), 10)). RunWith(w.stmtCache). Exec() if err != nil { diff --git a/cmd/soroban-rpc/internal/db/ledgerentry.go b/cmd/soroban-rpc/internal/db/ledgerentry.go index aaffed06..62677425 100644 --- a/cmd/soroban-rpc/internal/db/ledgerentry.go +++ b/cmd/soroban-rpc/internal/db/ledgerentry.go @@ -85,7 +85,7 @@ func (l ledgerEntryWriter) maybeFlush() error { func (l ledgerEntryWriter) flush() error { upsertCount := 0 upsertSQL := sq.StatementBuilder.RunWith(l.stmtCache).Replace(ledgerEntriesTableName) - var deleteKeys = make([]string, 0, len(l.keyToEntryBatch)) + deleteKeys := make([]string, 0, len(l.keyToEntryBatch)) upsertCacheUpdates := make(map[string]*string, len(l.keyToEntryBatch)) for key, entry := range l.keyToEntryBatch { diff --git a/cmd/soroban-rpc/internal/db/migration.go b/cmd/soroban-rpc/internal/db/migration.go index 2ed97946..8ca9d702 100644 --- a/cmd/soroban-rpc/internal/db/migration.go +++ b/cmd/soroban-rpc/internal/db/migration.go @@ -128,17 +128,17 @@ func newGuardedDataMigration(ctx context.Context, uniqueMigrationName string, fa metaKey := "Migration" + uniqueMigrationName + "Done" previouslyMigrated, err := getMetaBool(ctx, migrationDB, metaKey) if err != nil && !errors.Is(err, ErrEmptyDB) { - migrationDB.Rollback() + err = errors.Join(err, migrationDB.Rollback()) return nil, err } latestLedger, err := NewLedgerEntryReader(db).GetLatestLedgerSequence(ctx) if err != nil && err != ErrEmptyDB { - migrationDB.Rollback() + err = errors.Join(err, migrationDB.Rollback()) return nil, fmt.Errorf("failed to get latest ledger sequence: %w", err) } applier, err := factory.New(migrationDB, latestLedger) if err != nil { - migrationDB.Rollback() + err = errors.Join(err, migrationDB.Rollback()) return nil, err } guardedMigration := &guardedMigration{ diff --git a/cmd/soroban-rpc/internal/db/mocks.go b/cmd/soroban-rpc/internal/db/mocks.go index d2dfba4f..a5e97530 100644 --- a/cmd/soroban-rpc/internal/db/mocks.go +++ b/cmd/soroban-rpc/internal/db/mocks.go @@ -105,6 +105,8 @@ func (m *mockLedgerReader) StreamAllLedgers(ctx context.Context, f StreamLedgerF return nil } -var _ TransactionReader = &mockTransactionHandler{} -var _ TransactionWriter = &mockTransactionHandler{} -var _ LedgerReader = &mockLedgerReader{} +var ( + _ TransactionReader = &mockTransactionHandler{} + _ TransactionWriter = &mockTransactionHandler{} + _ LedgerReader = &mockLedgerReader{} +) diff --git a/cmd/soroban-rpc/internal/db/transaction.go b/cmd/soroban-rpc/internal/db/transaction.go index 099b4a15..43856945 100644 --- a/cmd/soroban-rpc/internal/db/transaction.go +++ b/cmd/soroban-rpc/internal/db/transaction.go @@ -237,9 +237,9 @@ func (txn *transactionHandler) getTransactionByHash(ctx context.Context, hash xd } rowQ := sq. Select("t.application_order", "lcm.meta"). - From(fmt.Sprintf("%s t", transactionTableName)). - Join(fmt.Sprintf("%s lcm ON (t.ledger_sequence = lcm.sequence)", ledgerCloseMetaTableName)). - Where(sq.Eq{"t.hash": []byte(hash[:])}). + From(transactionTableName + " t"). + Join(ledgerCloseMetaTableName + " lcm ON (t.ledger_sequence = lcm.sequence)"). + Where(sq.Eq{"t.hash": hash[:]}). Limit(1) if err := txn.db.Select(ctx, &rows, rowQ); err != nil { diff --git a/cmd/soroban-rpc/internal/events/events.go b/cmd/soroban-rpc/internal/events/events.go index b724fbf9..d9c3aa65 100644 --- a/cmd/soroban-rpc/internal/events/events.go +++ b/cmd/soroban-rpc/internal/events/events.go @@ -8,6 +8,7 @@ import ( "time" "github.com/prometheus/client_golang/prometheus" + "github.com/stellar/go/ingest" "github.com/stellar/go/xdr" @@ -19,7 +20,9 @@ type event struct { diagnosticEventXDR []byte txIndex uint32 eventIndex uint32 - txHash *xdr.Hash // intentionally stored as a pointer to save memory (amortized as soon as there are two events in a transaction) + // intentionally stored as a pointer to save memory + // (amortized as soon as there are two events in a transaction) + txHash *xdr.Hash } func (e event) cursor(ledgerSeq uint32) Cursor { diff --git a/cmd/soroban-rpc/internal/feewindow/feewindow.go b/cmd/soroban-rpc/internal/feewindow/feewindow.go index 4adc4880..a65210e3 100644 --- a/cmd/soroban-rpc/internal/feewindow/feewindow.go +++ b/cmd/soroban-rpc/internal/feewindow/feewindow.go @@ -1,3 +1,4 @@ +//nolint:mnd // percentile numbers are not really magical package feewindow import ( @@ -173,7 +174,6 @@ func (fw *FeeWindows) IngestFees(meta xdr.LedgerCloseMeta) error { } feePerOp := feeCharged / uint64(len(ops)) classicFees = append(classicFees, feePerOp) - } bucket := ledgerbucketwindow.LedgerBucket[[]uint64]{ LedgerSeq: meta.LedgerSequence(), diff --git a/cmd/soroban-rpc/internal/ingest/ledgerentry.go b/cmd/soroban-rpc/internal/ingest/ledgerentry.go index 9e4cc01d..d9fdc35c 100644 --- a/cmd/soroban-rpc/internal/ingest/ledgerentry.go +++ b/cmd/soroban-rpc/internal/ingest/ledgerentry.go @@ -7,6 +7,7 @@ import ( "time" "github.com/prometheus/client_golang/prometheus" + "github.com/stellar/go/ingest" "github.com/stellar/go/xdr" diff --git a/cmd/soroban-rpc/internal/ingest/service.go b/cmd/soroban-rpc/internal/ingest/service.go index 54ccbef4..86a2b445 100644 --- a/cmd/soroban-rpc/internal/ingest/service.go +++ b/cmd/soroban-rpc/internal/ingest/service.go @@ -9,6 +9,7 @@ import ( "github.com/cenkalti/backoff/v4" "github.com/prometheus/client_golang/prometheus" + "github.com/stellar/go/historyarchive" "github.com/stellar/go/ingest" backends "github.com/stellar/go/ingest/ledgerbackend" @@ -18,10 +19,9 @@ import ( "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/daemon/interfaces" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/db" + "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/events" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/feewindow" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/util" - - "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/events" ) const ( diff --git a/cmd/soroban-rpc/internal/ingest/service_test.go b/cmd/soroban-rpc/internal/ingest/service_test.go index 78f42494..32b55327 100644 --- a/cmd/soroban-rpc/internal/ingest/service_test.go +++ b/cmd/soroban-rpc/internal/ingest/service_test.go @@ -8,11 +8,12 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stellar/go/ingest/ledgerbackend" "github.com/stellar/go/network" supportlog "github.com/stellar/go/support/log" "github.com/stellar/go/xdr" - "github.com/stretchr/testify/assert" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/daemon/interfaces" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/db" diff --git a/cmd/soroban-rpc/internal/integrationtest/infrastructure/test.go b/cmd/soroban-rpc/internal/integrationtest/infrastructure/test.go index e54168d0..9279ae77 100644 --- a/cmd/soroban-rpc/internal/integrationtest/infrastructure/test.go +++ b/cmd/soroban-rpc/internal/integrationtest/infrastructure/test.go @@ -18,20 +18,20 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stellar/go/clients/stellarcore" "github.com/stellar/go/keypair" proto "github.com/stellar/go/protocols/stellarcore" supportlog "github.com/stellar/go/support/log" "github.com/stellar/go/txnbuild" "github.com/stellar/go/xdr" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/ledgerbucketwindow" - "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/methods" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/config" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/daemon" + "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/ledgerbucketwindow" + "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/methods" ) const ( diff --git a/cmd/soroban-rpc/internal/jsonrpc.go b/cmd/soroban-rpc/internal/jsonrpc.go index 014a75a1..01d0efeb 100644 --- a/cmd/soroban-rpc/internal/jsonrpc.go +++ b/cmd/soroban-rpc/internal/jsonrpc.go @@ -14,6 +14,7 @@ import ( "github.com/go-chi/chi/middleware" "github.com/prometheus/client_golang/prometheus" "github.com/rs/cors" + "github.com/stellar/go/support/log" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/config" @@ -139,7 +140,7 @@ func NewJSONRPCHandler(cfg *config.Config, params HandlerParams) Handler { // While we transition from in-memory to database-oriented history storage, // the on-disk (transaction) retention window will always be larger than the // in-memory (events) one. - var retentionWindow = cfg.TransactionLedgerRetentionWindow + retentionWindow := cfg.TransactionLedgerRetentionWindow handlers := []struct { methodName string diff --git a/cmd/soroban-rpc/internal/ledgerbucketwindow/ledgerbucketwindow.go b/cmd/soroban-rpc/internal/ledgerbucketwindow/ledgerbucketwindow.go index ee91427c..fe0eb58e 100644 --- a/cmd/soroban-rpc/internal/ledgerbucketwindow/ledgerbucketwindow.go +++ b/cmd/soroban-rpc/internal/ledgerbucketwindow/ledgerbucketwindow.go @@ -43,7 +43,12 @@ func (w *LedgerBucketWindow[T]) Append(bucket LedgerBucket[T]) (*LedgerBucket[T] if length > 0 { expectedLedgerSequence := w.buckets[w.start].LedgerSeq + length if expectedLedgerSequence != bucket.LedgerSeq { - return &LedgerBucket[T]{}, fmt.Errorf("error appending ledgers: ledgers not contiguous: expected ledger sequence %v but received %v", expectedLedgerSequence, bucket.LedgerSeq) + err := fmt.Errorf( + "error appending ledgers: ledgers not contiguous: expected ledger sequence %v but received %v", + expectedLedgerSequence, + bucket.LedgerSeq, + ) + return &LedgerBucket[T]{}, err } } diff --git a/cmd/soroban-rpc/internal/methods/get_events.go b/cmd/soroban-rpc/internal/methods/get_events.go index 841ec192..6eb705f2 100644 --- a/cmd/soroban-rpc/internal/methods/get_events.go +++ b/cmd/soroban-rpc/internal/methods/get_events.go @@ -123,9 +123,11 @@ func (g *GetEventsRequest) Matches(event xdr.DiagnosticEvent) bool { return false } -const EventTypeSystem = "system" -const EventTypeContract = "contract" -const EventTypeDiagnostic = "diagnostic" +const ( + EventTypeSystem = "system" + EventTypeContract = "contract" + EventTypeDiagnostic = "diagnostic" +) var eventTypeFromXDR = map[xdr.ContractEventType]string{ xdr.ContractEventTypeSystem: EventTypeSystem, @@ -201,8 +203,10 @@ func (e *EventFilter) matchesTopics(event xdr.ContractEvent) bool { type TopicFilter []SegmentFilter -const minTopicCount = 1 -const maxTopicCount = 4 +const ( + minTopicCount = 1 + maxTopicCount = 4 +) func (t *TopicFilter) Valid() error { if len(*t) < minTopicCount { diff --git a/cmd/soroban-rpc/internal/methods/get_fee_stats.go b/cmd/soroban-rpc/internal/methods/get_fee_stats.go index 0e02896a..73ebfd3a 100644 --- a/cmd/soroban-rpc/internal/methods/get_fee_stats.go +++ b/cmd/soroban-rpc/internal/methods/get_fee_stats.go @@ -4,6 +4,7 @@ import ( "context" "github.com/creachadair/jrpc2" + "github.com/stellar/go/support/log" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/db" @@ -48,7 +49,6 @@ func convertFeeDistribution(distribution feewindow.FeeDistribution) FeeDistribut TransactionCount: distribution.FeeCount, LedgerCount: distribution.LedgerCount, } - } type GetFeeStatsResult struct { diff --git a/cmd/soroban-rpc/internal/methods/get_ledger_entries.go b/cmd/soroban-rpc/internal/methods/get_ledger_entries.go index c3f2b617..551e371a 100644 --- a/cmd/soroban-rpc/internal/methods/get_ledger_entries.go +++ b/cmd/soroban-rpc/internal/methods/get_ledger_entries.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/creachadair/jrpc2" + "github.com/stellar/go/support/log" "github.com/stellar/go/xdr" diff --git a/cmd/soroban-rpc/internal/methods/get_ledger_entry.go b/cmd/soroban-rpc/internal/methods/get_ledger_entry.go index 910d2155..a43e4b92 100644 --- a/cmd/soroban-rpc/internal/methods/get_ledger_entry.go +++ b/cmd/soroban-rpc/internal/methods/get_ledger_entry.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/creachadair/jrpc2" + "github.com/stellar/go/support/log" "github.com/stellar/go/xdr" @@ -24,7 +25,8 @@ type GetLedgerEntryResponse struct { LastModifiedLedger uint32 `json:"lastModifiedLedgerSeq"` LatestLedger uint32 `json:"latestLedger"` // The ledger sequence until the entry is live, available for entries that have associated ttl ledger entries. - LiveUntilLedgerSeq *uint32 `json:"LiveUntilLedgerSeq,omitempty"` + // TODO: it should had been `liveUntilLedgerSeq` :( + LiveUntilLedgerSeq *uint32 `json:"LiveUntilLedgerSeq,omitempty"` //nolint:tagliatelle } // NewGetLedgerEntryHandler returns a json rpc handler to retrieve the specified ledger entry from stellar core diff --git a/cmd/soroban-rpc/internal/methods/get_transaction.go b/cmd/soroban-rpc/internal/methods/get_transaction.go index ad0dac59..37ef5f3a 100644 --- a/cmd/soroban-rpc/internal/methods/get_transaction.go +++ b/cmd/soroban-rpc/internal/methods/get_transaction.go @@ -8,6 +8,7 @@ import ( "fmt" "github.com/creachadair/jrpc2" + "github.com/stellar/go/support/log" "github.com/stellar/go/xdr" diff --git a/cmd/soroban-rpc/internal/methods/get_transactions.go b/cmd/soroban-rpc/internal/methods/get_transactions.go index baea5a72..b450622e 100644 --- a/cmd/soroban-rpc/internal/methods/get_transactions.go +++ b/cmd/soroban-rpc/internal/methods/get_transactions.go @@ -9,6 +9,7 @@ import ( "github.com/creachadair/jrpc2" "github.com/creachadair/jrpc2/handler" + "github.com/stellar/go/ingest" "github.com/stellar/go/support/errors" "github.com/stellar/go/support/log" @@ -151,7 +152,7 @@ LedgerLoop: } } - // Initialise tx reader. + // Initialize tx reader. reader, err := ingest.NewLedgerTransactionReaderFromLedgerCloseMeta(h.networkPassphrase, ledger) if err != nil { return GetTransactionsResponse{}, &jrpc2.Error{ diff --git a/cmd/soroban-rpc/internal/methods/get_version_info.go b/cmd/soroban-rpc/internal/methods/get_version_info.go index 9aa562a1..6c3053a3 100644 --- a/cmd/soroban-rpc/internal/methods/get_version_info.go +++ b/cmd/soroban-rpc/internal/methods/get_version_info.go @@ -2,26 +2,29 @@ package methods import ( "context" + "github.com/creachadair/jrpc2" "github.com/creachadair/jrpc2/handler" + "github.com/stellar/go/support/log" + "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/config" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/daemon/interfaces" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/db" ) type GetVersionInfoResponse struct { - Version string `json:"version"` - CommitHash string `json:"commit_hash"` - BuildTimestamp string `json:"build_time_stamp"` - CaptiveCoreVersion string `json:"captive_core_version"` - ProtocolVersion uint32 `json:"protocol_version"` + Version string `json:"version"` + // TODO: to be fixed by https://github.com/stellar/soroban-rpc/pull/164 + CommitHash string `json:"commit_hash"` //nolint:tagliatelle + BuildTimestamp string `json:"build_time_stamp"` //nolint:tagliatelle + CaptiveCoreVersion string `json:"captive_core_version"` //nolint:tagliatelle + ProtocolVersion uint32 `json:"protocol_version"` //nolint:tagliatelle } func NewGetVersionInfoHandler(logger *log.Entry, ledgerEntryReader db.LedgerEntryReader, ledgerReader db.LedgerReader, daemon interfaces.Daemon) jrpc2.Handler { coreClient := daemon.CoreClient() return handler.New(func(ctx context.Context) (GetVersionInfoResponse, error) { - var captiveCoreVersion string info, err := coreClient.Info(ctx) if err != nil { diff --git a/cmd/soroban-rpc/internal/methods/health.go b/cmd/soroban-rpc/internal/methods/health.go index 267b7206..b1db3f75 100644 --- a/cmd/soroban-rpc/internal/methods/health.go +++ b/cmd/soroban-rpc/internal/methods/health.go @@ -6,6 +6,7 @@ import ( "time" "github.com/creachadair/jrpc2" + "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/db" ) @@ -27,7 +28,7 @@ func NewHealthCheck( if err != nil || ledgerRange.LastLedger.Sequence < 1 { extra := "" if err != nil { - extra = fmt.Sprintf(": %s", err.Error()) + extra = ": " + err.Error() } return HealthCheckResult{}, jrpc2.Error{ Code: jrpc2.InternalError, diff --git a/cmd/soroban-rpc/internal/methods/send_transaction.go b/cmd/soroban-rpc/internal/methods/send_transaction.go index c8e476be..8bd92b07 100644 --- a/cmd/soroban-rpc/internal/methods/send_transaction.go +++ b/cmd/soroban-rpc/internal/methods/send_transaction.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "github.com/creachadair/jrpc2" + "github.com/stellar/go/network" proto "github.com/stellar/go/protocols/stellarcore" "github.com/stellar/go/support/log" diff --git a/cmd/soroban-rpc/internal/methods/simulate_transaction.go b/cmd/soroban-rpc/internal/methods/simulate_transaction.go index 9ad98d80..5b66836c 100644 --- a/cmd/soroban-rpc/internal/methods/simulate_transaction.go +++ b/cmd/soroban-rpc/internal/methods/simulate_transaction.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/creachadair/jrpc2" + "github.com/stellar/go/support/log" "github.com/stellar/go/xdr" @@ -76,7 +77,7 @@ func (l *LedgerEntryChangeType) Parse(s string) error { return nil } -func (l *LedgerEntryChangeType) UnmarshalJSON(data []byte) (err error) { +func (l *LedgerEntryChangeType) UnmarshalJSON(data []byte) error { var s string if err := json.Unmarshal(data, &s); err != nil { return err @@ -158,7 +159,6 @@ type PreflightGetter interface { // NewSimulateTransactionHandler returns a json rpc handler to run preflight simulations func NewSimulateTransactionHandler(logger *log.Entry, ledgerEntryReader db.LedgerEntryReader, ledgerReader db.LedgerReader, daemon interfaces.Daemon, getter PreflightGetter) jrpc2.Handler { - return NewHandler(func(ctx context.Context, request SimulateTransactionRequest) SimulateTransactionResponse { var txEnvelope xdr.TransactionEnvelope if err := xdr.SafeUnmarshalBase64(request.Transaction, &txEnvelope); err != nil { @@ -288,7 +288,7 @@ func base64EncodeSlice(in [][]byte) []string { func getBucketListSizeAndProtocolVersion(ctx context.Context, ledgerReader db.LedgerReader, latestLedger uint32) (uint64, uint32, error) { // obtain bucket size - var closeMeta, ok, err = ledgerReader.GetLedger(ctx, latestLedger) + closeMeta, ok, err := ledgerReader.GetLedger(ctx, latestLedger) if err != nil { return 0, 0, err } diff --git a/cmd/soroban-rpc/internal/network/backlogQ.go b/cmd/soroban-rpc/internal/network/backlogQ.go index 6a8f691b..b4b2791c 100644 --- a/cmd/soroban-rpc/internal/network/backlogQ.go +++ b/cmd/soroban-rpc/internal/network/backlogQ.go @@ -2,15 +2,17 @@ package network import ( "context" + "math" "net/http" "sync/atomic" "github.com/creachadair/jrpc2" + "github.com/stellar/go/support/errors" "github.com/stellar/go/support/log" ) -const RequestBacklogQueueNoLimit = maxUint +const RequestBacklogQueueNoLimit = math.MaxUint64 // The gauge is a subset of prometheus.Gauge, and it allows us to mock the // gauge usage for testing purposes without requiring the implementation of the true @@ -83,7 +85,6 @@ func (q *backlogHTTPQLimiter) ServeHTTP(res http.ResponseWriter, req *http.Reque } } defer func() { - atomic.AddUint64(&q.pending, ^uint64(0)) if q.gauge != nil { q.gauge.Dec() diff --git a/cmd/soroban-rpc/internal/network/backlogQ_test.go b/cmd/soroban-rpc/internal/network/backlogQ_test.go index 3fb05959..fb738e56 100644 --- a/cmd/soroban-rpc/internal/network/backlogQ_test.go +++ b/cmd/soroban-rpc/internal/network/backlogQ_test.go @@ -43,17 +43,17 @@ func TestBacklogQueueLimiter_HttpNonBlocking(t *testing.T) { testGauge := &TestingGauge{} limiter := MakeHTTPBacklogQueueLimiter(adding, testGauge, requestsSizeLimit, logCounter.Entry()) for i := 1; i < 50; i++ { - n := rand.Int63n(int64(requestsSizeLimit)) //nolint:gosec + requestCount := rand.Int63n(int64(requestsSizeLimit)) require.Zero(t, int(testGauge.count)) - wg.Add(int(n)) - for k := n; k > 0; k-- { + wg.Add(int(requestCount)) + for k := requestCount; k > 0; k-- { go func() { limiter.ServeHTTP(nil, nil) wg.Done() }() } wg.Wait() - require.Equal(t, uint64(n), sum) + require.Equal(t, uint64(requestCount), sum) require.Zero(t, int(testGauge.count)) sum = 0 } @@ -75,10 +75,10 @@ func TestBacklogQueueLimiter_JrpcNonBlocking(t *testing.T) { testGauge := &TestingGauge{} limiter := MakeJrpcBacklogQueueLimiter(adding.Handle, testGauge, requestsSizeLimit, logCounter.Entry()) for i := 1; i < 50; i++ { - n := rand.Int63n(int64(requestsSizeLimit)) //nolint:gosec + requestCount := rand.Int63n(int64(requestsSizeLimit)) require.Zero(t, int(testGauge.count)) - wg.Add(int(n)) - for k := n; k > 0; k-- { + wg.Add(int(requestCount)) + for k := requestCount; k > 0; k-- { go func() { _, err := limiter.Handle(context.Background(), nil) require.Nil(t, err) @@ -87,7 +87,7 @@ func TestBacklogQueueLimiter_JrpcNonBlocking(t *testing.T) { } wg.Wait() require.Zero(t, int(testGauge.count)) - require.Equal(t, uint64(n), sum) + require.Equal(t, uint64(requestCount), sum) sum = 0 } require.Equal(t, [7]int{0, 0, 0, 0, 0, 0, 0}, logCounter.writtenLogEntries) @@ -204,7 +204,7 @@ func TestBacklogQueueLimiter_JrpcBlocking(t *testing.T) { for i := queueSize / 2; i < queueSize; i++ { go func() { _, err := limiter.Handle(context.Background(), &jrpc2.Request{}) - require.Nil(t, err) + require.NoError(t, err) secondBlockingGroupWg.Done() }() } @@ -214,7 +214,7 @@ func TestBacklogQueueLimiter_JrpcBlocking(t *testing.T) { // now, try to place additional entry - which should be blocked. var res TestingResponseWriter _, err := limiter.Handle(context.Background(), &jrpc2.Request{}) - require.NotNil(t, err) + require.Error(t, err) require.Equal(t, [7]int{0, 0, 0, 0, 1, 0, 0}, logCounter.writtenLogEntries) secondBlockingGroupWg.Add(int(queueSize) - int(queueSize)/2) diff --git a/cmd/soroban-rpc/internal/network/requestdurationlimiter.go b/cmd/soroban-rpc/internal/network/requestdurationlimiter.go index 141b2486..c5af738f 100644 --- a/cmd/soroban-rpc/internal/network/requestdurationlimiter.go +++ b/cmd/soroban-rpc/internal/network/requestdurationlimiter.go @@ -2,19 +2,20 @@ package network import ( "context" + "math" "net/http" "reflect" "runtime" "time" "github.com/creachadair/jrpc2" + "github.com/stellar/go/support/log" + "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/util" ) -const maxUint = ^uint64(0) //18446744073709551615 -const maxInt = int64(maxUint >> 1) // 9223372036854775807 -const maxDuration = time.Duration(maxInt) +const maxDuration = time.Duration(math.MaxInt64) const RequestDurationLimiterNoLimit = maxDuration @@ -46,7 +47,8 @@ func MakeHTTPRequestDurationLimiter( limitThreshold time.Duration, warningCounter increasingCounter, limitCounter increasingCounter, - logger *log.Entry) *httpRequestDurationLimiter { + logger *log.Entry, +) http.Handler { // make sure the warning threshold is less then the limit threshold; otherwise, just set it to the limit threshold. if warningThreshold > limitThreshold { warningThreshold = limitThreshold @@ -83,10 +85,12 @@ func makeBufferedResponseWriter(rw http.ResponseWriter) *bufferedResponseWriter func (w *bufferedResponseWriter) Header() http.Header { return w.header } + func (w *bufferedResponseWriter) Write(buf []byte) (int, error) { w.buffer = append(w.buffer, buf...) return len(buf), nil } + func (w *bufferedResponseWriter) WriteHeader(statusCode int) { w.statusCode = statusCode } @@ -192,7 +196,7 @@ func (q *httpRequestDurationLimiter) ServeHTTP(res http.ResponseWriter, req *htt } } -type rpcRequestDurationLimiter struct { +type RPCRequestDurationLimiter struct { jrpcDownstreamHandler jrpc2.Handler requestDurationLimiter } @@ -203,13 +207,14 @@ func MakeJrpcRequestDurationLimiter( limitThreshold time.Duration, warningCounter increasingCounter, limitCounter increasingCounter, - logger *log.Entry) *rpcRequestDurationLimiter { + logger *log.Entry, +) *RPCRequestDurationLimiter { // make sure the warning threshold is less then the limit threshold; otherwise, just set it to the limit threshold. if warningThreshold > limitThreshold { warningThreshold = limitThreshold } - return &rpcRequestDurationLimiter{ + return &RPCRequestDurationLimiter{ jrpcDownstreamHandler: downstream, requestDurationLimiter: requestDurationLimiter{ warningThreshold: warningThreshold, @@ -221,7 +226,10 @@ func MakeJrpcRequestDurationLimiter( } } -func (q *rpcRequestDurationLimiter) Handle(ctx context.Context, req *jrpc2.Request) (interface{}, error) { +// TODO: this function is too complicated we should fix this and remove the nolint:gocognit +// +//nolint:gocognit,cyclop +func (q *RPCRequestDurationLimiter) Handle(ctx context.Context, req *jrpc2.Request) (interface{}, error) { if q.limitThreshold == RequestDurationLimiterNoLimit { // if specified max duration, pass-through return q.jrpcDownstreamHandler(ctx, req) diff --git a/cmd/soroban-rpc/internal/network/requestdurationlimiter_test.go b/cmd/soroban-rpc/internal/network/requestdurationlimiter_test.go index 5bc3a40f..9854d57c 100644 --- a/cmd/soroban-rpc/internal/network/requestdurationlimiter_test.go +++ b/cmd/soroban-rpc/internal/network/requestdurationlimiter_test.go @@ -214,11 +214,11 @@ func TestJRPCRequestDurationLimiter_Limiting(t *testing.T) { i int }{1} err := client.CallResult(context.Background(), "method", req, &res) - require.NotNil(t, err) + require.Error(t, err) jrpcError, ok := err.(*jrpc2.Error) require.True(t, ok) require.Equal(t, ErrRequestExceededProcessingLimitThreshold.Code, jrpcError.Code) - require.Equal(t, nil, res) + require.Nil(t, res) require.Zero(t, warningCounter.count) require.Equal(t, int64(1), limitCounter.count) require.Equal(t, [7]int{0, 0, 0, 0, 1, 0, 0}, logCounter.writtenLogEntries) diff --git a/cmd/soroban-rpc/internal/preflight/pool.go b/cmd/soroban-rpc/internal/preflight/pool.go index 3ea704d8..c6f8b1fc 100644 --- a/cmd/soroban-rpc/internal/preflight/pool.go +++ b/cmd/soroban-rpc/internal/preflight/pool.go @@ -8,6 +8,7 @@ import ( "time" "github.com/prometheus/client_golang/prometheus" + "github.com/stellar/go/support/log" "github.com/stellar/go/xdr" diff --git a/cmd/soroban-rpc/internal/preflight/preflight.go b/cmd/soroban-rpc/internal/preflight/preflight.go index 37ddcc9b..b79be958 100644 --- a/cmd/soroban-rpc/internal/preflight/preflight.go +++ b/cmd/soroban-rpc/internal/preflight/preflight.go @@ -1,18 +1,6 @@ +//nolint:lll // CGO LDFLAG definitions are long package preflight -import ( - "context" - "fmt" - "runtime/cgo" - "time" - "unsafe" - - "github.com/stellar/go/support/log" - "github.com/stellar/go/xdr" - - "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/db" -) - /* #include "../../lib/preflight.h" #include @@ -29,6 +17,19 @@ import ( */ import "C" +import ( + "context" + "fmt" + "runtime/cgo" + "time" + "unsafe" + + "github.com/stellar/go/support/log" + "github.com/stellar/go/xdr" + + "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/db" +) + type snapshotSourceHandle struct { readTx db.LedgerEntryReadTx logger *log.Entry @@ -36,6 +37,8 @@ type snapshotSourceHandle struct { const ( defaultInstructionLeeway uint64 = 0 + // Current base reserve is 0.5XLM (in stroops) + defaultBaseReserve = 5_000_000 ) // SnapshotSourceGet takes a LedgerKey XDR in base64 string and returns its matching LedgerEntry XDR in base64 string @@ -156,7 +159,7 @@ func GoXDRDiffVector(xdrDiffVector C.xdr_diff_vector_t) []XDRDiff { return result } -func GetPreflight(ctx context.Context, params PreflightParameters) (Preflight, error) { +func GetPreflight(_ context.Context, params PreflightParameters) (Preflight, error) { switch params.OpBody.Type { case xdr.OperationTypeInvokeHostFunction: return getInvokeHostFunctionPreflight(params) @@ -173,16 +176,15 @@ func getLedgerInfo(params PreflightParameters) (C.ledger_info_t, error) { return C.ledger_info_t{}, err } - li := C.ledger_info_t{ + ledgerInfo := C.ledger_info_t{ network_passphrase: C.CString(params.NetworkPassphrase), sequence_number: C.uint32_t(simulationLedgerSeq), protocol_version: C.uint32_t(params.ProtocolVersion), timestamp: C.uint64_t(time.Now().Unix()), - // Current base reserve is 0.5XLM (in stroops) - base_reserve: 5_000_000, - bucket_list_size: C.uint64_t(params.BucketListSize), + base_reserve: defaultBaseReserve, + bucket_list_size: C.uint64_t(params.BucketListSize), } - return li, nil + return ledgerInfo, nil } func getFootprintTtlPreflight(params PreflightParameters) (Preflight, error) { @@ -193,13 +195,13 @@ func getFootprintTtlPreflight(params PreflightParameters) (Preflight, error) { opBodyCXDR := CXDR(opBodyXDR) footprintXDR, err := params.Footprint.MarshalBinary() if err != nil { - return Preflight{}, err + return Preflight{}, fmt.Errorf("cannot marshal footprint: %w", err) } footprintCXDR := CXDR(footprintXDR) handle := cgo.NewHandle(snapshotSourceHandle{params.LedgerEntryReadTx, params.Logger}) defer handle.Delete() - li, err := getLedgerInfo(params) + ledgerInfo, err := getLedgerInfo(params) if err != nil { return Preflight{}, err } @@ -208,7 +210,7 @@ func getFootprintTtlPreflight(params PreflightParameters) (Preflight, error) { C.uintptr_t(handle), opBodyCXDR, footprintCXDR, - li, + ledgerInfo, ) FreeGoXDR(opBodyCXDR) @@ -240,7 +242,7 @@ func getInvokeHostFunctionPreflight(params PreflightParameters) (Preflight, erro return Preflight{}, err } sourceAccountCXDR := CXDR(sourceAccountXDR) - li, err := getLedgerInfo(params) + ledgerInfo, err := getLedgerInfo(params) if err != nil { return Preflight{}, err } @@ -254,7 +256,7 @@ func getInvokeHostFunctionPreflight(params PreflightParameters) (Preflight, erro C.uintptr_t(handle), invokeHostFunctionCXDR, sourceAccountCXDR, - li, + ledgerInfo, resourceConfig, C.bool(params.EnableDebug), ) diff --git a/cmd/soroban-rpc/internal/util/panicgroup.go b/cmd/soroban-rpc/internal/util/panicgroup.go index b131e91c..9bb77b9b 100644 --- a/cmd/soroban-rpc/internal/util/panicgroup.go +++ b/cmd/soroban-rpc/internal/util/panicgroup.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/prometheus/client_golang/prometheus" + "github.com/stellar/go/support/log" ) @@ -62,7 +63,7 @@ func (pg *panicGroup) recoverRoutine(fn func()) { return } cs := getPanicCallStack(recoverRes, fn) - if len(cs) <= 0 { + if len(cs) == 0 { return } if pg.log != nil { @@ -90,7 +91,7 @@ func getPanicCallStack(recoverRes any, fn func()) (outCallStack []string) { } // CallStack returns an array of strings representing the current call stack. The method is -// tuned for the purpose of panic handler, and used as a helper in contructing the list of entries we want +// tuned for the purpose of panic handler, and used as a helper in constructing the list of entries we want // to write to the log / stderr / telemetry. func CallStack(recoverRes any, topLevelFunctionName string, lastCallstackMethod string, unwindStackLines int) (callStack []string) { if topLevelFunctionName != "" { diff --git a/cmd/soroban-rpc/main.go b/cmd/soroban-rpc/main.go index ffa61d71..002a0ee8 100644 --- a/cmd/soroban-rpc/main.go +++ b/cmd/soroban-rpc/main.go @@ -5,6 +5,7 @@ import ( "os" "github.com/spf13/cobra" + supportlog "github.com/stellar/go/support/log" goxdr "github.com/stellar/go/xdr" @@ -27,7 +28,7 @@ func main() { fmt.Fprintln(os.Stderr, err) os.Exit(1) } - cfg.HistoryArchiveUserAgent = fmt.Sprintf("soroban-rpc/%s", config.Version) + cfg.HistoryArchiveUserAgent = "soroban-rpc/" + config.Version daemon.MustNew(&cfg, supportlog.New()).Run() }, } @@ -37,6 +38,7 @@ func main() { Short: "Print version information and exit", Run: func(_ *cobra.Command, _ []string) { if config.CommitHash == "" { + //nolint:forbidigo fmt.Printf("soroban-rpc dev\n") } else { // avoid printing the branch for the main branch