From 37d50608da0d5476b46798933e0effca0b3f1075 Mon Sep 17 00:00:00 2001 From: Alfonso Acosta Date: Tue, 18 Jun 2024 22:30:33 +0200 Subject: [PATCH 1/6] Add workaround for captive code bug in integration tests (#223) --- .../integrationtest/infrastructure/test.go | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/cmd/soroban-rpc/internal/integrationtest/infrastructure/test.go b/cmd/soroban-rpc/internal/integrationtest/infrastructure/test.go index 820fae41..e54168d0 100644 --- a/cmd/soroban-rpc/internal/integrationtest/infrastructure/test.go +++ b/cmd/soroban-rpc/internal/integrationtest/infrastructure/test.go @@ -194,7 +194,7 @@ func (i *Test) spawnContainers() { i.runSuccessfulComposeCommand(upCmd...) if i.runRPCInContainer() { i.rpcContainerLogsCommand = i.getComposeCommand("logs", "--no-log-prefix", "-f", "rpc") - writer := testLogWriter{t: i.t, prefix: fmt.Sprintf(`rpc="container" version="%s" `, i.rpcContainerVersion)} + writer := newTestLogWriter(i.t, fmt.Sprintf(`rpc="container" version="%s" `, i.rpcContainerVersion)) i.rpcContainerLogsCommand.Stdout = writer i.rpcContainerLogsCommand.Stderr = writer require.NoError(i.t, i.rpcContainerLogsCommand.Start()) @@ -397,12 +397,34 @@ func (i *Test) generateRPCConfigFile(rpcConfig rpcConfig) { require.NoError(i.t, err) } -type testLogWriter struct { - t *testing.T - prefix string +func newTestLogWriter(t *testing.T, prefix string) *testLogWriter { + tw := &testLogWriter{t: t, prefix: prefix} + t.Cleanup(func() { + tw.testDoneMx.Lock() + tw.testDone = true + tw.testDoneMx.Unlock() + }) + return tw } -func (tw testLogWriter) Write(p []byte) (n int, err error) { +type testLogWriter struct { + t *testing.T + prefix string + testDoneMx sync.RWMutex + testDone bool +} + +func (tw *testLogWriter) Write(p []byte) (n int, err error) { + tw.testDoneMx.RLock() + if tw.testDone { + // Workaround for https://github.com/stellar/go/issues/5342 + // and https://github.com/stellar/go/issues/5350, which causes a race condition + // in test logging + // TODO: remove once the tickets are fixed + tw.testDoneMx.RUnlock() + return len(p), nil + } + tw.testDoneMx.RUnlock() all := strings.TrimSpace(string(p)) lines := strings.Split(all, "\n") for _, l := range lines { @@ -423,7 +445,7 @@ func (i *Test) createRPCDaemon(c rpcConfig) *daemon.Daemon { cfg.HistoryArchiveUserAgent = fmt.Sprintf("soroban-rpc/%s", config.Version) logger := supportlog.New() - logger.SetOutput(testLogWriter{t: i.t, prefix: `rpc="daemon" `}) + logger.SetOutput(newTestLogWriter(i.t, `rpc="daemon" `)) return daemon.MustNew(&cfg, logger) } From 6f92bbf69f309d0001a5803794638cde640ea36a Mon Sep 17 00:00:00 2001 From: Alfonso Acosta Date: Thu, 20 Jun 2024 13:18:00 +0200 Subject: [PATCH 2/6] 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 From 0083ced1eed38cf45b9d95a7ad4ab8dab7efee1f Mon Sep 17 00:00:00 2001 From: Alfonso Acosta Date: Thu, 20 Jun 2024 18:16:56 +0200 Subject: [PATCH 3/6] Refactor GitHub setup-go action (#227) --- .github/actions/setup-go/action.yml | 90 +++++++++++++------------- .github/workflows/dependency-check.yml | 12 ++-- .github/workflows/e2e.yml | 18 +++--- .github/workflows/golang.yml | 9 +-- .github/workflows/rust.yml | 2 +- .github/workflows/soroban-rpc.yml | 23 ++----- 6 files changed, 70 insertions(+), 84 deletions(-) diff --git a/.github/actions/setup-go/action.yml b/.github/actions/setup-go/action.yml index 1bfd4a41..2d157acc 100644 --- a/.github/actions/setup-go/action.yml +++ b/.github/actions/setup-go/action.yml @@ -1,55 +1,55 @@ name: 'Setup the Go environment' description: 'Installs go and restores/saves the build/module cache' -inputs: - go-version: - required: true runs: using: "composite" steps: - - name: Set up Go - uses: actions/setup-go@v2 - with: - go-version: ${{ inputs.go-version }} - stable: ${{ !(contains(inputs.go-version, 'beta') || contains(inputs.go-version, 'rc')) }} + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.22' + # unfortunately we cannot use the provided caching because it uses the + # same cache for all workflows/jobs, leading to undesired cache clashes, + # causing uncached test runs etc ... + # You can see the cache key at https://github.com/actions/setup-go/blob/4e0b6c77c6448caafaff5eed51516cad78e7639a/src/cache-restore.ts#L34 + # There is a ticket to add prefixes for the cache, which should solve it https://github.com/actions/setup-go/issues/358 + cache: false - # Restore original modification time of files based on the date of the most - # recent commit that modified them as mtimes affect the Go test cache. - - name: Restore modification time of checkout files - shell: bash - run: | - # Set a base, fixed modification time of all directories. - # git-restore-mtime doesn't set the mtime of all directories. - # (see https://github.com/MestreLion/git-tools/issues/47 for details) - touch -m -t '201509301646' $(find . -type d -not -path '.git/*') - # Restore original modification time from git. git clone sets the - # modification time to the current time, but Go tests that access fixtures - # get invalidated if their modification times change. - sudo apt-get install -y git-restore-mtime - git restore-mtime + # Restore original modification time of files based on the date of the most + # recent commit that modified them as mtimes affect the Go test cache. + # See https://github.com/golang/go/issues/58571 for details + - name: Restore modification time of checkout files + uses: chetan/git-restore-mtime-action@075f9bc9d159805603419d50f794bd9f33252ebe - # The PREFIX must uniquely identify the specific instance of a job executing. - - shell: bash - run: echo 'PREFIX=${{ github.workflow }}-${{ github.job }}-${{ runner.os }}-${{ inputs.go-version }}-matrix(${{ join(matrix.*,'|') }})' >> $GITHUB_ENV - # Cache the Go Modules downloaded during the job. - - uses: actions/cache@v2 - with: - path: ~/go/pkg/mod - key: ${{ env.PREFIX }}-go-mod-${{ hashFiles('**/go.sum') }} - restore-keys: ${{ env.PREFIX }}-go-mod- + # KEY_PREFIX must uniquely identify the specific instance of a job executing. + - shell: bash + run: | + echo 'KEY_PREFIX=${{ github.workflow }}-${{ github.job }}-${{ runner.os }}-${{ inputs.go-version }}-matrix(${{ join(matrix.*,'|') }})' >> $GITHUB_OUTPUT + echo "GOCACHE=$(go env GOCACHE)" >> $GITHUB_OUTPUT + echo "GOMODCACHE=$(go env GOMODCACHE)" >> $GITHUB_OUTPUT + if [ ${{ runner.os }} != 'Windows' ]; then echo SUDO='sudo' >> $GITHUB_OUTPUT; fi + id: variables - # Cache any build and test artifacts during the job, which will speed up - # rebuilds and cause test runs to skip tests that have no reason to rerun. - - uses: actions/cache@v2 - with: - path: ~/.cache/go-build - key: ${{ env.PREFIX }}-go-build-${{ github.ref }}-${{ hashFiles('**', '!.git') }} - restore-keys: | - ${{ env.PREFIX }}-go-build-${{ github.ref }}- - ${{ env.PREFIX }}-go-build- + # Cache the Go Modules downloaded during the job. + - uses: actions/cache@v4 + with: + path: ${{ steps.variables.outputs.GOMODCACHE }} + key: ${{ steps.variables.outputs.KEY_PREFIX }}-go-mod-${{ hashFiles('**/go.sum') }} + restore-keys: ${{ steps.variables.outputs.KEY_PREFIX }}-go-mod- + + # Cache any build and test artifacts during the job, which will speed up + # rebuilds and cause test runs to skip tests that have no reason to rerun. + - uses: actions/cache@v4 + with: + path: ${{ steps.variables.outputs.GOCACHE }} + key: ${{ steps.variables.outputs.KEY_PREFIX }}-go-build-${{ github.ref }}-${{ hashFiles('**', '!.git') }} + restore-keys: | + ${{ steps.variables.outputs.KEY_PREFIX }}-go-build-${{ github.ref }}- + ${{ steps.variables.outputs.KEY_PREFIX }}-go-build- + + # Reset the cache for master/protected branches, to ensure they build and run the tests from zero + # and that the module cache is cleaned (otherwise it accumulates orphan dependencies over time). + - if: github.ref_protected + shell: bash + run: ${{ steps.variables.outputs.SUDO }} rm -rf ${{ steps.variables.outputs.GOMODCACHE }} ${{ steps.variables.outputs.GOCACHE }} - # Reset the cache for master/protected branches, to ensure they build and run the tests from zero - # and that the module cache is cleaned (otherwise it accumulates orphan dependencies over time). - - if: github.ref_protected - shell: bash - run: sudo rm -rf ~/.cache/go-build ~/go/pkg/mod diff --git a/.github/workflows/dependency-check.yml b/.github/workflows/dependency-check.yml index 79a14aa7..dc865935 100644 --- a/.github/workflows/dependency-check.yml +++ b/.github/workflows/dependency-check.yml @@ -2,7 +2,7 @@ name: Dependency sanity checker on: push: - branches: [main, release/**] + branches: [ main, release/** ] pull_request: defaults: @@ -13,14 +13,14 @@ jobs: dependency-sanity-checker: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: rustup update - - uses: actions/setup-go@v3 - with: - go-version: 1.22 + - uses: stellar/actions/rust-cache@main + - uses: ./.github/actions/setup-go - run: scripts/check-dependencies.bash + validate-rust-git-rev-deps: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: stellar/actions/rust-check-git-rev-deps@main diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index ce1677ad..f14121e9 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -2,7 +2,7 @@ name: Soroban Tools e2e on: push: - branches: [main, release/**] + branches: [ main, release/** ] pull_request: jobs: @@ -10,7 +10,7 @@ jobs: name: System tests strategy: matrix: - scenario-filter: ["^TestDappDevelop$/^.*$"] + scenario-filter: [ "^TestDappDevelop$/^.*$" ] runs-on: ubuntu-latest-4-cores env: # the gh tag of system-test repo version to run @@ -28,7 +28,7 @@ jobs: # or set SYSTEM_TEST_CORE_GIT_REF to empty, and set SYSTEM_TEST_CORE_IMAGE # to pull a pre-compiled image from dockerhub instead SYSTEM_TEST_CORE_IMAGE: stellar/stellar-core:20 - SYSTEM_TEST_CORE_IMAGE_BIN_PATH: /usr/bin/stellar-core + SYSTEM_TEST_CORE_IMAGE_BIN_PATH: /usr/bin/stellar-core # sets the version of rust toolchain that will be pre-installed in the # test runtime environment, tests invoke rustc/cargo @@ -42,8 +42,8 @@ jobs: # option #2, set the version of stellar-sdk used as a ref to a gh repo if # a value is set on SYSTEM_TEST_JS_STELLAR_SDK_GH_REPO, it takes # precedence over any SYSTEM_TEST_JS_STELLAR_SDK_NPM_VERSION - SYSTEM_TEST_JS_STELLAR_SDK_GH_REPO: - SYSTEM_TEST_JS_STELLAR_SDK_GH_REF: + SYSTEM_TEST_JS_STELLAR_SDK_GH_REPO: + SYSTEM_TEST_JS_STELLAR_SDK_GH_REF: # the version of rs-stellar-xdr to use for quickstart SYSTEM_TEST_RS_XDR_GIT_REF: v20.0.2 @@ -59,18 +59,18 @@ jobs: SYSTEM_TEST_SOROBAN_EXAMPLES_GIT_HASH: "v20.0.0" SYSTEM_TEST_SOROBAN_EXAMPLES_GIT_REPO: "https://github.com/stellar/soroban-examples.git" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 name: checkout system-test with: repository: stellar/system-test ref: ${{ env.SYSTEM_TEST_GIT_REF }} path: system-test - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 name: checkout soroban-tools with: repository: stellar/soroban-tools path: soroban-tools - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 name: checkout soroban-rpc with: repository: stellar/soroban-rpc @@ -81,7 +81,7 @@ jobs: run: | rm -rf $GITHUB_WORKSPACE/system-test/js-stellar-sdk; - if: ${{ env.SYSTEM_TEST_JS_STELLAR_SDK_GH_REPO != ''}} - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: ${{ env.SYSTEM_TEST_JS_STELLAR_SDK_GH_REPO }} ref: ${{ env.SYSTEM_TEST_JS_STELLAR_SDK_GH_REF }} diff --git a/.github/workflows/golang.yml b/.github/workflows/golang.yml index a9726b9e..21db63bb 100644 --- a/.github/workflows/golang.yml +++ b/.github/workflows/golang.yml @@ -8,7 +8,7 @@ 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. + # Optional: allow the action to annotate code in the PR. checks: write jobs: @@ -16,14 +16,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # version v3.0.2 + uses: actions/checkout@v4 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: ./.github/actions/setup-go - uses: stellar/actions/rust-cache@main - name: Build libpreflight diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 6f9dd3fa..6b1cb36a 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -13,7 +13,7 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: rustup update - uses: stellar/actions/rust-cache@main - run: make rust-check diff --git a/.github/workflows/soroban-rpc.yml b/.github/workflows/soroban-rpc.yml index e9122e82..7edfe2e3 100644 --- a/.github/workflows/soroban-rpc.yml +++ b/.github/workflows/soroban-rpc.yml @@ -15,10 +15,9 @@ jobs: strategy: matrix: os: [ ubuntu-20.04, ubuntu-22.04 ] - go: [ 1.22 ] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: # For pull requests, build and test the PR head not a merge of the PR with the destination. ref: ${{ github.event.pull_request.head.sha || github.ref }} @@ -26,12 +25,10 @@ jobs: # Otherwise, the Go test cache will fail (due to the modification time of fixtures changing). fetch-depth: "0" - uses: ./.github/actions/setup-go - 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/... + - run: go test -race -timeout 25m ./cmd/soroban-rpc/... build: name: Build @@ -55,13 +52,8 @@ jobs: go_arch: amd64 runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 - # we cannot use our own ./.github/actions/setup-go action - # because it uses apt-get and some OSs (e.g. windows) don't have it - - uses: actions/setup-go@v3 - with: - go-version: 1.22 - + - uses: actions/checkout@v4 + - uses: ./.github/actions/setup-go # On windows, make sure we have the same compiler (linker) used by rust. # This is important since the symbols names won't match otherwise. - if: matrix.os == 'windows-latest' @@ -102,7 +94,6 @@ jobs: strategy: matrix: os: [ ubuntu-20.04, ubuntu-22.04 ] - go: [ 1.22 ] protocol-version: [ 20, 21 ] runs-on: ${{ matrix.os }} env: @@ -114,7 +105,7 @@ jobs: PROTOCOL_21_CORE_DEBIAN_PKG_VERSION: 21.0.1-1897.dfd3dbff1.focal PROTOCOL_21_CORE_DOCKER_IMG: stellar/unsafe-stellar-core:21.0.1-1897.dfd3dbff1.focal steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: # For pull requests, build and test the PR head not a merge of the PR with the destination. ref: ${{ github.event.pull_request.head.sha || github.ref }} @@ -123,8 +114,6 @@ jobs: fetch-depth: "0" - uses: ./.github/actions/setup-go - with: - go-version: ${{ matrix.go }} - name: Pull and set Stellar Core image shell: bash @@ -179,4 +168,4 @@ jobs: - name: Run Soroban RPC Integration Tests run: | - go test -race -timeout 20m ./cmd/soroban-rpc/internal/integrationtest/... + go test -race -timeout 20m ./cmd/soroban-rpc/internal/integrationtest/... From 6b0e71539add0aa34a0398ac1d00ba3fe1545fbb Mon Sep 17 00:00:00 2001 From: Alfonso Acosta Date: Thu, 20 Jun 2024 18:43:20 +0200 Subject: [PATCH 4/6] go: Fix more linter problems (#228) --- .golangci.yml | 17 ++- cmd/soroban-rpc/internal/config/flags.go | 141 +++++++++--------- .../internal/config/{config.go => main.go} | 2 +- .../config/{config_test.go => main_test.go} | 0 .../config/{config_option.go => option.go} | 55 ++++--- .../{config_option_test.go => option_test.go} | 24 +-- cmd/soroban-rpc/internal/config/options.go | 42 +++--- .../internal/config/options_test.go | 14 +- cmd/soroban-rpc/internal/config/parse.go | 20 ++- cmd/soroban-rpc/internal/config/toml_test.go | 3 +- cmd/soroban-rpc/internal/config/version.go | 1 + cmd/soroban-rpc/internal/daemon/daemon.go | 18 ++- .../internal/daemon/interfaces/noOpDaemon.go | 12 +- cmd/soroban-rpc/internal/db/db.go | 6 +- cmd/soroban-rpc/internal/db/ledger_test.go | 6 +- cmd/soroban-rpc/internal/db/ledgerentry.go | 8 +- .../internal/db/ledgerentry_test.go | 2 +- cmd/soroban-rpc/internal/db/migration.go | 1 - cmd/soroban-rpc/internal/db/transaction.go | 38 +++-- .../internal/db/transaction_test.go | 6 +- cmd/soroban-rpc/internal/events/cursor.go | 8 +- .../internal/events/events_test.go | 3 +- .../internal/feewindow/feewindow.go | 7 +- .../internal/feewindow/feewindow_test.go | 19 ++- .../internal/ingest/service_test.go | 5 +- .../integrationtest/get_fee_stats_test.go | 5 +- .../integrationtest/get_transactions_test.go | 9 +- .../integrationtest/get_version_info_test.go | 5 +- .../integrationtest/infrastructure/client.go | 7 +- .../infrastructure/contract.go | 3 +- .../integrationtest/infrastructure/test.go | 9 +- .../integrationtest/infrastructure/util.go | 16 +- .../internal/integrationtest/metrics_test.go | 8 +- .../internal/integrationtest/migrate_test.go | 4 +- .../integrationtest/transaction_test.go | 6 +- .../internal/integrationtest/upgrade_test.go | 3 +- cmd/soroban-rpc/internal/jsonrpc.go | 2 +- .../internal/methods/get_events.go | 4 +- .../methods/get_latest_ledger_test.go | 12 +- .../internal/methods/get_ledger_entries.go | 7 +- .../internal/methods/get_ledger_entry.go | 2 +- .../internal/methods/get_transaction_test.go | 1 - .../internal/methods/get_transactions.go | 10 +- .../internal/methods/get_transactions_test.go | 44 +++--- .../internal/methods/simulate_transaction.go | 12 +- .../methods/simulate_transaction_test.go | 3 +- cmd/soroban-rpc/internal/network/backlogQ.go | 17 +-- .../internal/network/backlogQ_test.go | 4 +- .../network/requestdurationlimiter.go | 3 + .../network/requestdurationlimiter_test.go | 5 +- .../internal/network/utils_test.go | 5 + cmd/soroban-rpc/internal/preflight/pool.go | 54 ++++--- .../internal/preflight/preflight.go | 14 +- .../internal/preflight/preflight_test.go | 19 ++- .../internal/util/panicgroup_test.go | 7 +- cmd/soroban-rpc/main.go | 2 + 56 files changed, 409 insertions(+), 351 deletions(-) rename cmd/soroban-rpc/internal/config/{config.go => main.go} (99%) rename cmd/soroban-rpc/internal/config/{config_test.go => main_test.go} (100%) rename cmd/soroban-rpc/internal/config/{config_option.go => option.go} (61%) rename cmd/soroban-rpc/internal/config/{config_option_test.go => option_test.go} (91%) diff --git a/.golangci.yml b/.golangci.yml index aca3ea8a..dcdfcad4 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -87,8 +87,10 @@ linters-settings: linters: enable-all: true disable: + # deprecated: - gomnd - execinquery + - depguard - nlreturn - godox @@ -101,23 +103,22 @@ linters: - wsl - wrapcheck - testpackage - # TODO: I didn't manage to make it accept short parameter names + # TODO: varnamelen: I didn't manage to make it accept short parameter names - varnamelen - # TODO: consider enabling it later on + # TODO: ireturn: consider enabling it later on - ireturn - godot presets: [ ] fast: false issues: - # Excluding configuration per-path, per-linter, per-text and per-source + # Exclude certain checks in test files exclude-rules: - - path: _test\.go - linters: - - gosec - - path: cmd/soroban-rpc/internal/integrationtest/infrastructure/ + - path: '^(.*_test\.go|cmd/soroban-rpc/internal/integrationtest/infrastructure/.*)$' linters: + - mnd - gosec - + - gochecknoglobals + - nosprintfhostport run: timeout: 10m diff --git a/cmd/soroban-rpc/internal/config/flags.go b/cmd/soroban-rpc/internal/config/flags.go index d313aa31..0c313460 100644 --- a/cmd/soroban-rpc/internal/config/flags.go +++ b/cmd/soroban-rpc/internal/config/flags.go @@ -1,3 +1,4 @@ +//nolint:forcetypeassert // this file uses several unchecked assertions package config import ( @@ -22,151 +23,153 @@ func (cfg *Config) AddFlags(cmd *cobra.Command) error { } // AddFlag adds a CLI flag for this option to the given flagset. -func (co *ConfigOption) AddFlag(flagset *pflag.FlagSet) error { +// +//nolint:funlen,cyclop +func (o *Option) AddFlag(flagset *pflag.FlagSet) error { // config options that has no names do not represent a valid flag. - if len(co.Name) == 0 { + if len(o.Name) == 0 { return nil } // Treat any option with a custom parser as a string option. - if co.CustomSetValue != nil { - if co.DefaultValue == nil { - co.DefaultValue = "" + if o.CustomSetValue != nil { + if o.DefaultValue == nil { + o.DefaultValue = "" } - flagset.String(co.Name, fmt.Sprint(co.DefaultValue), co.UsageText()) - co.flag = flagset.Lookup(co.Name) + flagset.String(o.Name, fmt.Sprint(o.DefaultValue), o.UsageText()) + o.flag = flagset.Lookup(o.Name) return nil } // Infer the type of the flag based on the type of the ConfigKey. This list // of options is based on the available flag types from pflags - switch co.ConfigKey.(type) { + switch o.ConfigKey.(type) { case *bool: - flagset.Bool(co.Name, co.DefaultValue.(bool), co.UsageText()) + flagset.Bool(o.Name, o.DefaultValue.(bool), o.UsageText()) case *time.Duration: - flagset.Duration(co.Name, co.DefaultValue.(time.Duration), co.UsageText()) + flagset.Duration(o.Name, o.DefaultValue.(time.Duration), o.UsageText()) case *float32: - flagset.Float32(co.Name, co.DefaultValue.(float32), co.UsageText()) + flagset.Float32(o.Name, o.DefaultValue.(float32), o.UsageText()) case *float64: - flagset.Float64(co.Name, co.DefaultValue.(float64), co.UsageText()) + flagset.Float64(o.Name, o.DefaultValue.(float64), o.UsageText()) case *net.IP: - flagset.IP(co.Name, co.DefaultValue.(net.IP), co.UsageText()) + flagset.IP(o.Name, o.DefaultValue.(net.IP), o.UsageText()) case *net.IPNet: - flagset.IPNet(co.Name, co.DefaultValue.(net.IPNet), co.UsageText()) + flagset.IPNet(o.Name, o.DefaultValue.(net.IPNet), o.UsageText()) case *int: - flagset.Int(co.Name, co.DefaultValue.(int), co.UsageText()) + flagset.Int(o.Name, o.DefaultValue.(int), o.UsageText()) case *int8: - flagset.Int8(co.Name, co.DefaultValue.(int8), co.UsageText()) + flagset.Int8(o.Name, o.DefaultValue.(int8), o.UsageText()) case *int16: - flagset.Int16(co.Name, co.DefaultValue.(int16), co.UsageText()) + flagset.Int16(o.Name, o.DefaultValue.(int16), o.UsageText()) case *int32: - flagset.Int32(co.Name, co.DefaultValue.(int32), co.UsageText()) + flagset.Int32(o.Name, o.DefaultValue.(int32), o.UsageText()) case *int64: - flagset.Int64(co.Name, co.DefaultValue.(int64), co.UsageText()) + flagset.Int64(o.Name, o.DefaultValue.(int64), o.UsageText()) case *[]int: - flagset.IntSlice(co.Name, co.DefaultValue.([]int), co.UsageText()) + flagset.IntSlice(o.Name, o.DefaultValue.([]int), o.UsageText()) case *[]int32: - flagset.Int32Slice(co.Name, co.DefaultValue.([]int32), co.UsageText()) + flagset.Int32Slice(o.Name, o.DefaultValue.([]int32), o.UsageText()) case *[]int64: - flagset.Int64Slice(co.Name, co.DefaultValue.([]int64), co.UsageText()) + flagset.Int64Slice(o.Name, o.DefaultValue.([]int64), o.UsageText()) case *string: // Set an empty string if no default was provided, since some value is always required for pflags - if co.DefaultValue == nil { - co.DefaultValue = "" + if o.DefaultValue == nil { + o.DefaultValue = "" } - flagset.String(co.Name, co.DefaultValue.(string), co.UsageText()) + flagset.String(o.Name, o.DefaultValue.(string), o.UsageText()) case *[]string: // Set an empty string if no default was provided, since some value is always required for pflags - if co.DefaultValue == nil { - co.DefaultValue = []string{} + if o.DefaultValue == nil { + o.DefaultValue = []string{} } - flagset.StringSlice(co.Name, co.DefaultValue.([]string), co.UsageText()) + flagset.StringSlice(o.Name, o.DefaultValue.([]string), o.UsageText()) case *uint: - flagset.Uint(co.Name, co.DefaultValue.(uint), co.UsageText()) + flagset.Uint(o.Name, o.DefaultValue.(uint), o.UsageText()) case *uint8: - flagset.Uint8(co.Name, co.DefaultValue.(uint8), co.UsageText()) + flagset.Uint8(o.Name, o.DefaultValue.(uint8), o.UsageText()) case *uint16: - flagset.Uint16(co.Name, co.DefaultValue.(uint16), co.UsageText()) + flagset.Uint16(o.Name, o.DefaultValue.(uint16), o.UsageText()) case *uint32: - flagset.Uint32(co.Name, co.DefaultValue.(uint32), co.UsageText()) + flagset.Uint32(o.Name, o.DefaultValue.(uint32), o.UsageText()) case *uint64: - flagset.Uint64(co.Name, co.DefaultValue.(uint64), co.UsageText()) + flagset.Uint64(o.Name, o.DefaultValue.(uint64), o.UsageText()) case *[]uint: - flagset.UintSlice(co.Name, co.DefaultValue.([]uint), co.UsageText()) + flagset.UintSlice(o.Name, o.DefaultValue.([]uint), o.UsageText()) default: - return fmt.Errorf("unexpected option type: %T", co.ConfigKey) + return fmt.Errorf("unexpected option type: %T", o.ConfigKey) } - co.flag = flagset.Lookup(co.Name) + o.flag = flagset.Lookup(o.Name) return nil } -func (co *ConfigOption) GetFlag(flagset *pflag.FlagSet) (interface{}, error) { +//nolint:cyclop +func (o *Option) GetFlag(flagset *pflag.FlagSet) (interface{}, error) { // Treat any option with a custom parser as a string option. - if co.CustomSetValue != nil { - return flagset.GetString(co.Name) + if o.CustomSetValue != nil { + return flagset.GetString(o.Name) } // Infer the type of the flag based on the type of the ConfigKey. This list // of options is based on the available flag types from pflags, and must // match the above in `AddFlag`. - switch co.ConfigKey.(type) { + switch o.ConfigKey.(type) { case *bool: - return flagset.GetBool(co.Name) + return flagset.GetBool(o.Name) case *time.Duration: - return flagset.GetDuration(co.Name) + return flagset.GetDuration(o.Name) case *float32: - return flagset.GetFloat32(co.Name) + return flagset.GetFloat32(o.Name) case *float64: - return flagset.GetFloat64(co.Name) + return flagset.GetFloat64(o.Name) case *net.IP: - return flagset.GetIP(co.Name) + return flagset.GetIP(o.Name) case *net.IPNet: - return flagset.GetIPNet(co.Name) + return flagset.GetIPNet(o.Name) case *int: - return flagset.GetInt(co.Name) + return flagset.GetInt(o.Name) case *int8: - return flagset.GetInt8(co.Name) + return flagset.GetInt8(o.Name) case *int16: - return flagset.GetInt16(co.Name) + return flagset.GetInt16(o.Name) case *int32: - return flagset.GetInt32(co.Name) + return flagset.GetInt32(o.Name) case *int64: - return flagset.GetInt64(co.Name) + return flagset.GetInt64(o.Name) case *[]int: - return flagset.GetIntSlice(co.Name) + return flagset.GetIntSlice(o.Name) case *[]int32: - return flagset.GetInt32Slice(co.Name) + return flagset.GetInt32Slice(o.Name) case *[]int64: - return flagset.GetInt64Slice(co.Name) + return flagset.GetInt64Slice(o.Name) case *string: - return flagset.GetString(co.Name) + return flagset.GetString(o.Name) case *[]string: - return flagset.GetStringSlice(co.Name) + return flagset.GetStringSlice(o.Name) case *uint: - return flagset.GetUint(co.Name) + return flagset.GetUint(o.Name) case *uint8: - return flagset.GetUint8(co.Name) + return flagset.GetUint8(o.Name) case *uint16: - return flagset.GetUint16(co.Name) + return flagset.GetUint16(o.Name) case *uint32: - return flagset.GetUint32(co.Name) + return flagset.GetUint32(o.Name) case *uint64: - return flagset.GetUint64(co.Name) + return flagset.GetUint64(o.Name) case *[]uint: - return flagset.GetUintSlice(co.Name) + return flagset.GetUintSlice(o.Name) default: - return nil, fmt.Errorf("unexpected option type: %T", co.ConfigKey) + return nil, fmt.Errorf("unexpected option type: %T", o.ConfigKey) } } // UsageText returns the string to use for the usage text of the option. The -// string returned will be the Usage defined on the ConfigOption, along with +// string returned will be the Usage defined on the Option, along with // the environment variable. -func (co *ConfigOption) UsageText() string { - envVar, hasEnvVar := co.getEnvKey() +func (o *Option) UsageText() string { + envVar, hasEnvVar := o.getEnvKey() if hasEnvVar { - return fmt.Sprintf("%s (%s)", co.Usage, envVar) - } else { - return co.Usage + return fmt.Sprintf("%s (%s)", o.Usage, envVar) } + return o.Usage } diff --git a/cmd/soroban-rpc/internal/config/config.go b/cmd/soroban-rpc/internal/config/main.go similarity index 99% rename from cmd/soroban-rpc/internal/config/config.go rename to cmd/soroban-rpc/internal/config/main.go index 2ce48459..1321feb6 100644 --- a/cmd/soroban-rpc/internal/config/config.go +++ b/cmd/soroban-rpc/internal/config/main.go @@ -71,7 +71,7 @@ type Config struct { MaxGetFeeStatsExecutionDuration time.Duration // We memoize these, so they bind to pflags correctly - optionsCache *ConfigOptions + optionsCache *Options flagset *pflag.FlagSet } diff --git a/cmd/soroban-rpc/internal/config/config_test.go b/cmd/soroban-rpc/internal/config/main_test.go similarity index 100% rename from cmd/soroban-rpc/internal/config/config_test.go rename to cmd/soroban-rpc/internal/config/main_test.go diff --git a/cmd/soroban-rpc/internal/config/config_option.go b/cmd/soroban-rpc/internal/config/option.go similarity index 61% rename from cmd/soroban-rpc/internal/config/config_option.go rename to cmd/soroban-rpc/internal/config/option.go index ffbdc936..2583a383 100644 --- a/cmd/soroban-rpc/internal/config/config_option.go +++ b/cmd/soroban-rpc/internal/config/option.go @@ -12,21 +12,22 @@ import ( "github.com/stellar/go/support/strutils" ) -// ConfigOptions is a group of ConfigOptions that can be for convenience +// Options is a group of Options that can be for convenience // initialized and set at the same time. -type ConfigOptions []*ConfigOption +type Options []*Option // Validate all the config options. -func (options ConfigOptions) Validate() error { - var missingOptions []errMissingRequiredOption +func (options Options) Validate() error { + var missingOptions []missingRequiredOptionError for _, option := range options { if option.Validate != nil { err := option.Validate(option) if err == nil { continue } - if missingOption, ok := err.(errMissingRequiredOption); ok { - missingOptions = append(missingOptions, missingOption) + var missingOptionErr missingRequiredOptionError + if ok := errors.As(err, &missingOptionErr); ok { + missingOptions = append(missingOptions, missingOptionErr) continue } return errors.New("Invalid config value for " + option.Name) @@ -39,28 +40,36 @@ func (options ConfigOptions) Validate() error { errString += "\n*\t" + missingOpt.strErr errString += "\n \t" + missingOpt.usage } - return &errMissingRequiredOption{strErr: errString} + return &missingRequiredOptionError{strErr: errString} } return nil } -// ConfigOption is a complete description of the configuration of a command line option -type ConfigOption struct { - Name string // e.g. "database-url" - EnvVar string // e.g. "DATABASE_URL". Defaults to uppercase/underscore representation of name - TomlKey string // e.g. "DATABASE_URL". Defaults to uppercase/underscore representation of name. - to omit from toml - Usage string // Help text - DefaultValue interface{} // A default if no option is provided. Omit or set to `nil` if no default - ConfigKey interface{} // Pointer to the final key in the linked Config struct - CustomSetValue func(*ConfigOption, interface{}) error // Optional function for custom validation/transformation - Validate func(*ConfigOption) error // Function called after loading all options, to validate the configuration - MarshalTOML func(*ConfigOption) (interface{}, error) +// Option is a complete description of the configuration of a command line option +type Option struct { + // e.g. "database-url" + Name string + // e.g. "DATABASE_URL".Defaults to uppercase/underscore representation of name + EnvVar string + // e.g. "DATABASE_URL". Defaults to uppercase/underscore representation of name. - to omit from toml + TomlKey string + // Help text + Usage string + // A default if no option is provided. Omit or set to `nil` if no default + DefaultValue interface{} + // Pointer to the final key in the linked Config struct + ConfigKey interface{} + // Optional function for custom validation/transformation + CustomSetValue func(*Option, interface{}) error + // Function called after loading all options, to validate the configuration + Validate func(*Option) error + MarshalTOML func(*Option) (interface{}, error) flag *pflag.Flag // The persistent flag that the config option is attached to } // Returns false if this option is omitted in the toml -func (o ConfigOption) getTomlKey() (string, bool) { +func (o Option) getTomlKey() (string, bool) { if o.TomlKey == "-" || o.TomlKey == "_" { return "", false } @@ -74,7 +83,7 @@ func (o ConfigOption) getTomlKey() (string, bool) { } // Returns false if this option is omitted in the env -func (o ConfigOption) getEnvKey() (string, bool) { +func (o Option) getEnvKey() (string, bool) { if o.EnvVar == "-" || o.EnvVar == "_" { return "", false } @@ -85,7 +94,7 @@ func (o ConfigOption) getEnvKey() (string, bool) { } // TODO: See if we can remove CustomSetValue into just SetValue/ParseValue -func (o *ConfigOption) setValue(i interface{}) (err error) { +func (o *Option) setValue(i interface{}) (err error) { if o.CustomSetValue != nil { return o.CustomSetValue(o, i) } @@ -99,7 +108,7 @@ func (o *ConfigOption) setValue(i interface{}) (err error) { err = fmt.Errorf("config option setting error ('%s') %v", o.Name, recoverRes) } }() - parser := func(option *ConfigOption, i interface{}) error { + parser := func(_ *Option, _ interface{}) error { return fmt.Errorf("no parser for flag %s", o.Name) } switch o.ConfigKey.(type) { @@ -124,7 +133,7 @@ func (o *ConfigOption) setValue(i interface{}) (err error) { return parser(o, i) } -func (o *ConfigOption) marshalTOML() (interface{}, error) { +func (o *Option) marshalTOML() (interface{}, error) { if o.MarshalTOML != nil { return o.MarshalTOML(o) } diff --git a/cmd/soroban-rpc/internal/config/config_option_test.go b/cmd/soroban-rpc/internal/config/option_test.go similarity index 91% rename from cmd/soroban-rpc/internal/config/config_option_test.go rename to cmd/soroban-rpc/internal/config/option_test.go index a6309cb3..83e9b5eb 100644 --- a/cmd/soroban-rpc/internal/config/config_option_test.go +++ b/cmd/soroban-rpc/internal/config/option_test.go @@ -12,39 +12,39 @@ import ( func TestConfigOptionGetTomlKey(t *testing.T) { // Explicitly set toml key - key, ok := ConfigOption{TomlKey: "TOML_KEY"}.getTomlKey() + key, ok := Option{TomlKey: "TOML_KEY"}.getTomlKey() assert.Equal(t, "TOML_KEY", key) assert.True(t, ok) // Explicitly disabled toml key via `-` - key, ok = ConfigOption{TomlKey: "-"}.getTomlKey() + key, ok = Option{TomlKey: "-"}.getTomlKey() assert.Equal(t, "", key) assert.False(t, ok) // Explicitly disabled toml key via `_` - key, ok = ConfigOption{TomlKey: "_"}.getTomlKey() + key, ok = Option{TomlKey: "_"}.getTomlKey() assert.Equal(t, "", key) assert.False(t, ok) // Fallback to env var - key, ok = ConfigOption{EnvVar: "ENV_VAR"}.getTomlKey() + key, ok = Option{EnvVar: "ENV_VAR"}.getTomlKey() assert.Equal(t, "ENV_VAR", key) assert.True(t, ok) // Env-var disabled, autogenerate from name - key, ok = ConfigOption{Name: "test-flag", EnvVar: "-"}.getTomlKey() + key, ok = Option{Name: "test-flag", EnvVar: "-"}.getTomlKey() assert.Equal(t, "TEST_FLAG", key) assert.True(t, ok) // Env-var not set, autogenerate from name - key, ok = ConfigOption{Name: "test-flag"}.getTomlKey() + key, ok = Option{Name: "test-flag"}.getTomlKey() assert.Equal(t, "TEST_FLAG", key) assert.True(t, ok) } func TestValidateRequired(t *testing.T) { var strVal string - o := &ConfigOption{ + o := &Option{ Name: "required-option", ConfigKey: &strVal, Validate: required, @@ -64,7 +64,7 @@ func TestValidateRequired(t *testing.T) { func TestValidatePositiveUint32(t *testing.T) { var val uint32 - o := &ConfigOption{ + o := &Option{ Name: "positive-option", ConfigKey: &val, Validate: positive, @@ -84,7 +84,7 @@ func TestValidatePositiveUint32(t *testing.T) { func TestValidatePositiveInt(t *testing.T) { var val int - o := &ConfigOption{ + o := &Option{ Name: "positive-option", ConfigKey: &val, Validate: positive, @@ -107,7 +107,7 @@ func TestValidatePositiveInt(t *testing.T) { } func TestUnassignableField(t *testing.T) { - var co ConfigOption + var co Option var b bool co.Name = "mykey" co.ConfigKey = &b @@ -117,7 +117,7 @@ func TestUnassignableField(t *testing.T) { } func TestNoParserForFlag(t *testing.T) { - var co ConfigOption + var co Option var invalidKey []time.Duration co.Name = "mykey" co.ConfigKey = &invalidKey @@ -256,7 +256,7 @@ func TestSetValue(t *testing.T) { }, } { t.Run(scenario.name, func(t *testing.T) { - co := ConfigOption{ + co := Option{ Name: scenario.name, ConfigKey: scenario.key, } diff --git a/cmd/soroban-rpc/internal/config/options.go b/cmd/soroban-rpc/internal/config/options.go index f417a7ee..e4838ab5 100644 --- a/cmd/soroban-rpc/internal/config/options.go +++ b/cmd/soroban-rpc/internal/config/options.go @@ -1,4 +1,4 @@ -//nolint:mnd // lots of magic constants due to default values +//nolint:mnd,lll // lots of magic constants and long lines due to default values and help strings package config import ( @@ -12,7 +12,6 @@ import ( "github.com/sirupsen/logrus" "github.com/stellar/go/network" - "github.com/stellar/go/support/errors" "github.com/stellar/go/support/strutils" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/ledgerbucketwindow" @@ -20,12 +19,15 @@ import ( const defaultHTTPEndpoint = "localhost:8000" -func (cfg *Config) options() ConfigOptions { +// TODO: refactor and remove the linter exceptions +// +//nolint:funlen,cyclop,maintidx +func (cfg *Config) options() Options { if cfg.optionsCache != nil { return *cfg.optionsCache } defaultStellarCoreBinaryPath, _ := exec.LookPath("stellar-core") - cfg.optionsCache = &ConfigOptions{ + cfg.optionsCache = &Options{ { Name: "config-path", EnvVar: "SOROBAN_RPC_CONFIG_PATH", @@ -56,7 +58,7 @@ func (cfg *Config) options() ConfigOptions { Name: "stellar-core-url", Usage: "URL used to query Stellar Core (local captive core by default)", ConfigKey: &cfg.StellarCoreURL, - Validate: func(co *ConfigOption) error { + Validate: func(_ *Option) error { // This is a bit awkward. We're actually setting a default, but we // can't do that until the config is fully parsed, so we do it as a // validator here. @@ -83,7 +85,7 @@ func (cfg *Config) options() ConfigOptions { Usage: "minimum log severity (debug, info, warn, error) to log", ConfigKey: &cfg.LogLevel, DefaultValue: logrus.InfoLevel, - CustomSetValue: func(option *ConfigOption, i interface{}) error { + CustomSetValue: func(option *Option, i interface{}) error { switch v := i.(type) { case nil: return nil @@ -102,7 +104,7 @@ func (cfg *Config) options() ConfigOptions { } return nil }, - MarshalTOML: func(option *ConfigOption) (interface{}, error) { + MarshalTOML: func(_ *Option) (interface{}, error) { return cfg.LogLevel.String(), nil }, }, @@ -111,15 +113,15 @@ func (cfg *Config) options() ConfigOptions { Usage: "format used for output logs (json or text)", ConfigKey: &cfg.LogFormat, DefaultValue: LogFormatText, - CustomSetValue: func(option *ConfigOption, i interface{}) error { + CustomSetValue: func(option *Option, i interface{}) error { switch v := i.(type) { case nil: return nil case string: - return errors.Wrapf( - cfg.LogFormat.UnmarshalText([]byte(v)), - "could not parse %s", + return fmt.Errorf( + "could not parse %s: %w", option.Name, + cfg.LogFormat.UnmarshalText([]byte(v)), ) case LogFormat: cfg.LogFormat = v @@ -130,7 +132,7 @@ func (cfg *Config) options() ConfigOptions { } return nil }, - MarshalTOML: func(option *ConfigOption) (interface{}, error) { + MarshalTOML: func(_ *Option) (interface{}, error) { return cfg.LogFormat.String() }, }, @@ -151,7 +153,7 @@ func (cfg *Config) options() ConfigOptions { Name: "captive-core-storage-path", Usage: "Storage location for Captive Core bucket data", ConfigKey: &cfg.CaptiveCoreStoragePath, - CustomSetValue: func(option *ConfigOption, i interface{}) error { + CustomSetValue: func(option *Option, i interface{}) error { switch v := i.(type) { case string: if v == "" || v == "." { @@ -255,7 +257,7 @@ func (cfg *Config) options() ConfigOptions { Usage: "Default cap on the amount of events included in a single getEvents response", ConfigKey: &cfg.DefaultEventsLimit, DefaultValue: uint(100), - Validate: func(co *ConfigOption) error { + Validate: func(_ *Option) error { if cfg.DefaultEventsLimit > cfg.MaxEventsLimit { return fmt.Errorf( "default-events-limit (%v) cannot exceed max-events-limit (%v)", @@ -277,7 +279,7 @@ func (cfg *Config) options() ConfigOptions { Usage: "Default cap on the amount of transactions included in a single getTransactions response", ConfigKey: &cfg.DefaultTransactionsLimit, DefaultValue: uint(50), - Validate: func(co *ConfigOption) error { + Validate: func(_ *Option) error { if cfg.DefaultTransactionsLimit > cfg.MaxTransactionsLimit { return fmt.Errorf( "default-transactions-limit (%v) cannot exceed max-transactions-limit (%v)", @@ -481,16 +483,16 @@ func (cfg *Config) options() ConfigOptions { return *cfg.optionsCache } -type errMissingRequiredOption struct { +type missingRequiredOptionError struct { strErr string usage string } -func (e errMissingRequiredOption) Error() string { +func (e missingRequiredOptionError) Error() string { return e.strErr } -func required(option *ConfigOption) error { +func required(option *Option) error { switch reflect.ValueOf(option.ConfigKey).Elem().Kind() { case reflect.Slice: if reflect.ValueOf(option.ConfigKey).Elem().Len() > 0 { @@ -524,10 +526,10 @@ func required(option *ConfigOption) error { advice = fmt.Sprintf(" Please %s, %s, or %s.", waysToSet[0], waysToSet[1], waysToSet[2]) } - return errMissingRequiredOption{strErr: fmt.Sprintf("%s is required.%s", option.Name, advice), usage: option.Usage} + return missingRequiredOptionError{strErr: fmt.Sprintf("%s is required.%s", option.Name, advice), usage: option.Usage} } -func positive(option *ConfigOption) error { +func positive(option *Option) error { switch v := option.ConfigKey.(type) { case *int, *int8, *int16, *int32, *int64: if reflect.ValueOf(v).Elem().Int() <= 0 { diff --git a/cmd/soroban-rpc/internal/config/options_test.go b/cmd/soroban-rpc/internal/config/options_test.go index 00b1654f..0478b628 100644 --- a/cmd/soroban-rpc/internal/config/options_test.go +++ b/cmd/soroban-rpc/internal/config/options_test.go @@ -15,7 +15,7 @@ func TestAllConfigKeysMustBePointers(t *testing.T) { for _, option := range cfg.options() { kind := reflect.ValueOf(option.ConfigKey).Type().Kind() if kind != reflect.Pointer { - t.Errorf("ConfigOption.ConfigKey must be a pointer, got %s for %s", kind, option.Name) + t.Errorf("Option.ConfigKey must be a pointer, got %s for %s", kind, option.Name) } } } @@ -33,7 +33,7 @@ func TestAllConfigFieldsMustHaveASingleOption(t *testing.T) { cfgType := cfgValue.Type() options := cfg.options() - optionsByField := map[uintptr]*ConfigOption{} + optionsByField := map[uintptr]*Option{} for _, option := range options { key := uintptr(reflect.ValueOf(option.ConfigKey).UnsafePointer()) if existing, ok := optionsByField[key]; ok { @@ -58,7 +58,7 @@ func TestAllConfigFieldsMustHaveASingleOption(t *testing.T) { // There should be an option which points to this field _, ok := optionsByField[fieldPointer] if !ok { - t.Errorf("Missing ConfigOption for field Config.%s", structField.Name) + t.Errorf("Missing Option for field Config.%s", structField.Name) } } } @@ -79,7 +79,7 @@ func TestAllOptionsMustHaveAUniqueValidTomlKey(t *testing.T) { // Allow us to explicitly exclude any fields on the Config struct, which are // not going to be in the toml. This should be the "Name" field of the - // ConfigOption we wish to exclude. + // Option we wish to exclude. excluded := map[string]bool{ "config-path": true, } @@ -91,12 +91,12 @@ func TestAllOptionsMustHaveAUniqueValidTomlKey(t *testing.T) { key, ok := option.getTomlKey() if excluded[option.Name] { if ok { - t.Errorf("Found unexpected toml key for excluded ConfigOption %s. Does the test need updating?", option.Name) + t.Errorf("Found unexpected toml key for excluded Option %s. Does the test need updating?", option.Name) } continue } if !ok { - t.Errorf("Missing toml key for ConfigOption %s", option.Name) + t.Errorf("Missing toml key for Option %s", option.Name) } if existing, ok := optionsByTomlKey[key]; ok { t.Errorf("Conflicting ConfigOptions %s and %s, have the same toml key: %s", existing, option.Name, key) @@ -104,6 +104,6 @@ func TestAllOptionsMustHaveAUniqueValidTomlKey(t *testing.T) { optionsByTomlKey[key] = option.Name // Ensure the keys are simple valid toml keys - assert.True(t, keyRegex.MatchString(key), "Invalid toml key for ConfigOption %s: %s", option.Name, key) + assert.True(t, keyRegex.MatchString(key), "Invalid toml key for Option %s: %s", option.Name, key) } } diff --git a/cmd/soroban-rpc/internal/config/parse.go b/cmd/soroban-rpc/internal/config/parse.go index 6001f5d7..58a5d80b 100644 --- a/cmd/soroban-rpc/internal/config/parse.go +++ b/cmd/soroban-rpc/internal/config/parse.go @@ -7,11 +7,9 @@ import ( "strconv" "strings" "time" - - "github.com/stellar/go/support/errors" ) -func parseBool(option *ConfigOption, i interface{}) error { +func parseBool(option *Option, i interface{}) error { switch v := i.(type) { case nil: return nil @@ -32,7 +30,7 @@ func parseBool(option *ConfigOption, i interface{}) error { return nil } -func parseInt(option *ConfigOption, i interface{}) error { +func parseInt(option *Option, i interface{}) error { switch v := i.(type) { case nil: return nil @@ -50,7 +48,7 @@ func parseInt(option *ConfigOption, i interface{}) error { return nil } -func parseUint(option *ConfigOption, i interface{}) error { +func parseUint(option *Option, i interface{}) error { switch v := i.(type) { case nil: return nil @@ -73,7 +71,7 @@ func parseUint(option *ConfigOption, i interface{}) error { return nil } -func parseFloat(option *ConfigOption, i interface{}) error { +func parseFloat(option *Option, i interface{}) error { switch v := i.(type) { case nil: return nil @@ -91,7 +89,7 @@ func parseFloat(option *ConfigOption, i interface{}) error { return nil } -func parseString(option *ConfigOption, i interface{}) error { +func parseString(option *Option, i interface{}) error { switch v := i.(type) { case nil: return nil @@ -103,7 +101,7 @@ func parseString(option *ConfigOption, i interface{}) error { return nil } -func parseUint32(option *ConfigOption, i interface{}) error { +func parseUint32(option *Option, i interface{}) error { switch v := i.(type) { case nil: return nil @@ -129,14 +127,14 @@ func parseUint32(option *ConfigOption, i interface{}) error { return nil } -func parseDuration(option *ConfigOption, i interface{}) error { +func parseDuration(option *Option, i interface{}) error { switch v := i.(type) { case nil: return nil case string: d, err := time.ParseDuration(v) if err != nil { - return errors.Wrapf(err, "could not parse duration: %q", v) + return fmt.Errorf("could not parse duration: %q: %w", v, err) } *option.ConfigKey.(*time.Duration) = d case time.Duration: @@ -149,7 +147,7 @@ func parseDuration(option *ConfigOption, i interface{}) error { return nil } -func parseStringSlice(option *ConfigOption, i interface{}) error { +func parseStringSlice(option *Option, i interface{}) error { switch v := i.(type) { case nil: return nil diff --git a/cmd/soroban-rpc/internal/config/toml_test.go b/cmd/soroban-rpc/internal/config/toml_test.go index 93fa1809..0b438996 100644 --- a/cmd/soroban-rpc/internal/config/toml_test.go +++ b/cmd/soroban-rpc/internal/config/toml_test.go @@ -8,9 +8,10 @@ import ( "time" "github.com/sirupsen/logrus" - "github.com/stellar/go/network" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/stellar/go/network" ) const basicToml = ` diff --git a/cmd/soroban-rpc/internal/config/version.go b/cmd/soroban-rpc/internal/config/version.go index 909fdaea..3e203dde 100644 --- a/cmd/soroban-rpc/internal/config/version.go +++ b/cmd/soroban-rpc/internal/config/version.go @@ -1,3 +1,4 @@ +//nolint:gochecknoglobals // allow global variables package config var ( diff --git a/cmd/soroban-rpc/internal/daemon/daemon.go b/cmd/soroban-rpc/internal/daemon/daemon.go index bf55fa4a..5ca3004b 100644 --- a/cmd/soroban-rpc/internal/daemon/daemon.go +++ b/cmd/soroban-rpc/internal/daemon/daemon.go @@ -51,7 +51,7 @@ type Daemon struct { db *db.DB jsonRPCHandler *internal.Handler logger *supportlog.Entry - preflightWorkerPool *preflight.PreflightWorkerPool + preflightWorkerPool *preflight.WorkerPool listener net.Listener server *http.Server adminListener net.Listener @@ -238,13 +238,15 @@ func MustNew(cfg *config.Config, logger *supportlog.Entry) *Daemon { ledgerEntryReader := db.NewLedgerEntryReader(dbConn) preflightWorkerPool := preflight.NewPreflightWorkerPool( - daemon, - cfg.PreflightWorkerCount, - cfg.PreflightWorkerQueueSize, - cfg.PreflightEnableDebug, - ledgerEntryReader, - cfg.NetworkPassphrase, - logger, + preflight.WorkerPoolConfig{ + Daemon: daemon, + WorkerCount: cfg.PreflightWorkerCount, + JobQueueCapacity: cfg.PreflightWorkerQueueSize, + EnableDebug: cfg.PreflightEnableDebug, + LedgerEntryReader: ledgerEntryReader, + NetworkPassphrase: cfg.NetworkPassphrase, + Logger: logger, + }, ) jsonRPCHandler := internal.NewJSONRPCHandler(cfg, internal.HandlerParams{ diff --git a/cmd/soroban-rpc/internal/daemon/interfaces/noOpDaemon.go b/cmd/soroban-rpc/internal/daemon/interfaces/noOpDaemon.go index 79a63971..db8d513d 100644 --- a/cmd/soroban-rpc/internal/daemon/interfaces/noOpDaemon.go +++ b/cmd/soroban-rpc/internal/daemon/interfaces/noOpDaemon.go @@ -10,29 +10,29 @@ import ( // The noOpDeamon is a dummy daemon implementation, supporting the Daemon interface. // Used only in testing. -type noOpDaemon struct { +type NoOpDaemon struct { metricsRegistry *prometheus.Registry metricsNamespace string coreClient noOpCoreClient } -func MakeNoOpDeamon() *noOpDaemon { - return &noOpDaemon{ +func MakeNoOpDeamon() *NoOpDaemon { + return &NoOpDaemon{ metricsRegistry: prometheus.NewRegistry(), metricsNamespace: "soroban_rpc", coreClient: noOpCoreClient{}, } } -func (d *noOpDaemon) MetricsRegistry() *prometheus.Registry { +func (d *NoOpDaemon) MetricsRegistry() *prometheus.Registry { return prometheus.NewRegistry() // so that you can register metrics many times } -func (d *noOpDaemon) MetricsNamespace() string { +func (d *NoOpDaemon) MetricsNamespace() string { return d.metricsNamespace } -func (d *noOpDaemon) CoreClient() CoreClient { +func (d *NoOpDaemon) CoreClient() CoreClient { return d.coreClient } diff --git a/cmd/soroban-rpc/internal/db/db.go b/cmd/soroban-rpc/internal/db/db.go index 966f8cd8..1767f610 100644 --- a/cmd/soroban-rpc/internal/db/db.go +++ b/cmd/soroban-rpc/internal/db/db.go @@ -4,6 +4,7 @@ import ( "context" "database/sql" "embed" + "errors" "fmt" "strconv" "sync" @@ -14,7 +15,6 @@ import ( migrate "github.com/rubenv/sql-migrate" "github.com/stellar/go/support/db" - "github.com/stellar/go/support/errors" "github.com/stellar/go/support/log" "github.com/stellar/go/xdr" @@ -63,12 +63,12 @@ func openSQLiteDB(dbFilePath string) (*db.Session, error) { // 3. Use synchronous=NORMAL, which is faster and still safe in WAL mode. session, err := db.Open("sqlite3", fmt.Sprintf("file:%s?_journal_mode=WAL&_wal_autocheckpoint=0&_synchronous=NORMAL", dbFilePath)) if err != nil { - return nil, errors.Wrap(err, "open failed") + return nil, fmt.Errorf("open failed: %w", err) } if err = runSQLMigrations(session.DB.DB, "sqlite3"); err != nil { _ = session.Close() - return nil, errors.Wrap(err, "could not run SQL migrations") + return nil, fmt.Errorf("could not run SQL migrations: %w", err) } return session, nil } diff --git a/cmd/soroban-rpc/internal/db/ledger_test.go b/cmd/soroban-rpc/internal/db/ledger_test.go index 25369fac..a40bc255 100644 --- a/cmd/soroban-rpc/internal/db/ledger_test.go +++ b/cmd/soroban-rpc/internal/db/ledger_test.go @@ -15,8 +15,10 @@ import ( "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/daemon/interfaces" ) -var passphrase = network.FutureNetworkPassphrase -var logger = log.DefaultLogger +var ( + passphrase = network.FutureNetworkPassphrase + logger = log.DefaultLogger +) func createLedger(ledgerSequence uint32) xdr.LedgerCloseMeta { return xdr.LedgerCloseMeta{ diff --git a/cmd/soroban-rpc/internal/db/ledgerentry.go b/cmd/soroban-rpc/internal/db/ledgerentry.go index 62677425..60e3a259 100644 --- a/cmd/soroban-rpc/internal/db/ledgerentry.go +++ b/cmd/soroban-rpc/internal/db/ledgerentry.go @@ -4,12 +4,12 @@ import ( "context" "crypto/sha256" "database/sql" + "errors" "fmt" sq "github.com/Masterminds/squirrel" "github.com/stellar/go/support/db" - "github.com/stellar/go/support/errors" "github.com/stellar/go/xdr" ) @@ -54,7 +54,7 @@ func (l ledgerEntryWriter) UpsertLedgerEntry(entry xdr.LedgerEntry) error { // because the key can be derived from the entry. key, err := entry.LedgerKey() if err != nil { - return errors.Wrap(err, "could not get ledger key from entry") + return fmt.Errorf("could not get ledger key from entry: %w", err) } encodedKey, err := encodeLedgerKey(l.buffer, key) @@ -304,7 +304,7 @@ func (l *ledgerEntryReadTx) GetLedgerEntries(keys ...xdr.LedgerKey) ([]LedgerKey } var entry xdr.LedgerEntry if err := xdr.SafeUnmarshal([]byte(encodedEntry), &entry); err != nil { - return nil, errors.Wrap(err, "cannot decode ledger entry from DB") + return nil, fmt.Errorf("cannot decode ledger entry from DB: %w", err) } if k2e.encodedTTLKey == nil { result = append(result, LedgerKeyAndEntry{k2e.key, entry, nil}) @@ -317,7 +317,7 @@ func (l *ledgerEntryReadTx) GetLedgerEntries(keys ...xdr.LedgerKey) ([]LedgerKey } var ttlEntry xdr.LedgerEntry if err := xdr.SafeUnmarshal([]byte(encodedTTLEntry), &ttlEntry); err != nil { - return nil, errors.Wrap(err, "cannot decode TTL ledger entry from DB") + return nil, fmt.Errorf("cannot decode TTL ledger entry from DB: %w", err) } liveUntilSeq := uint32(ttlEntry.Data.Ttl.LiveUntilLedgerSeq) result = append(result, LedgerKeyAndEntry{k2e.key, entry, &liveUntilSeq}) diff --git a/cmd/soroban-rpc/internal/db/ledgerentry_test.go b/cmd/soroban-rpc/internal/db/ledgerentry_test.go index 34b1b41e..08526709 100644 --- a/cmd/soroban-rpc/internal/db/ledgerentry_test.go +++ b/cmd/soroban-rpc/internal/db/ledgerentry_test.go @@ -13,6 +13,7 @@ import ( "github.com/stellar/go/support/log" "github.com/stellar/go/xdr" + "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/daemon/interfaces" ) @@ -483,7 +484,6 @@ forloop: t.Log(msg) } } - } func benchmarkLedgerEntry(b *testing.B, cached bool) { diff --git a/cmd/soroban-rpc/internal/db/migration.go b/cmd/soroban-rpc/internal/db/migration.go index 8ca9d702..74a88f87 100644 --- a/cmd/soroban-rpc/internal/db/migration.go +++ b/cmd/soroban-rpc/internal/db/migration.go @@ -172,7 +172,6 @@ func (g *guardedMigration) Commit(ctx context.Context) error { } err := setMetaBool(ctx, g.db, g.guardMetaKey, true) if err != nil { - g.Rollback(ctx) return errors.Join(err, g.Rollback(ctx)) } return g.db.Commit() diff --git a/cmd/soroban-rpc/internal/db/transaction.go b/cmd/soroban-rpc/internal/db/transaction.go index 43856945..fdb8b5b9 100644 --- a/cmd/soroban-rpc/internal/db/transaction.go +++ b/cmd/soroban-rpc/internal/db/transaction.go @@ -3,6 +3,7 @@ package db import ( "context" "encoding/hex" + "errors" "fmt" "time" @@ -11,7 +12,6 @@ import ( "github.com/stellar/go/ingest" "github.com/stellar/go/support/db" - "github.com/stellar/go/support/errors" "github.com/stellar/go/support/log" "github.com/stellar/go/xdr" @@ -80,16 +80,18 @@ func (txn *transactionHandler) InsertTransactions(lcm xdr.LedgerCloseMeta) error reader, err := ingest.NewLedgerTransactionReaderFromLedgerCloseMeta(txn.passphrase, lcm) if err != nil { - return errors.Wrapf(err, - "failed to open transaction reader for ledger %d", - lcm.LedgerSequence()) + return fmt.Errorf( + "failed to open transaction reader for ledger %d: %w", + lcm.LedgerSequence(), + err, + ) } transactions := make(map[xdr.Hash]ingest.LedgerTransaction, txCount) for i := 0; i < txCount; i++ { tx, err := reader.Read() if err != nil { - return errors.Wrapf(err, "failed reading tx %d", i) + return fmt.Errorf("failed reading tx %d: %w", i, err) } // For fee-bump transactions, we store lookup entries for both the outer @@ -163,12 +165,12 @@ func (txn *transactionHandler) GetLedgerRange(ctx context.Context) (ledgerbucket "m2", ).ToSql() if err != nil { - return ledgerRange, errors.Wrap(err, "couldn't build ledger range query") + return ledgerRange, fmt.Errorf("couldn't build ledger range query: %w", err) } var lcms []xdr.LedgerCloseMeta if err = txn.db.Select(ctx, &lcms, newestQ.Suffix("UNION ALL "+sql, args...)); err != nil { - return ledgerRange, errors.Wrap(err, "couldn't query ledger range") + return ledgerRange, fmt.Errorf("couldn't query ledger range: %w", err) } else if len(lcms) < 2 { // There is almost certainly a row, but we want to avoid a race condition // with ingestion as well as support test cases from an empty DB, so we need @@ -244,18 +246,22 @@ func (txn *transactionHandler) getTransactionByHash(ctx context.Context, hash xd if err := txn.db.Select(ctx, &rows, rowQ); err != nil { return xdr.LedgerCloseMeta{}, ingest.LedgerTransaction{}, - errors.Wrapf(err, "db read failed for txhash %s", hex.EncodeToString(hash[:])) + fmt.Errorf("db read failed for txhash %s: %w", hex.EncodeToString(hash[:]), err) } else if len(rows) < 1 { return xdr.LedgerCloseMeta{}, ingest.LedgerTransaction{}, ErrNoTransaction } txIndex, lcm := rows[0].TxIndex, rows[0].Lcm reader, err := ingest.NewLedgerTransactionReaderFromLedgerCloseMeta(txn.passphrase, lcm) - reader.Seek(txIndex - 1) if err != nil { return lcm, ingest.LedgerTransaction{}, - errors.Wrapf(err, "failed to index to tx %d in ledger %d (txhash=%s)", - txIndex, lcm.LedgerSequence(), hash) + fmt.Errorf("failed to create ledger reader: %w", err) + } + err = reader.Seek(txIndex - 1) + if err != nil { + return lcm, ingest.LedgerTransaction{}, + fmt.Errorf("failed to index to tx %d in ledger %d (txhash=%s): %w", + txIndex, lcm.LedgerSequence(), hash, err) } ledgerTx, err := reader.Read() @@ -278,25 +284,25 @@ func ParseTransaction(lcm xdr.LedgerCloseMeta, ingestTx ingest.LedgerTransaction } if tx.Result, err = ingestTx.Result.Result.MarshalBinary(); err != nil { - return tx, errors.Wrap(err, "couldn't encode transaction Result") + return tx, fmt.Errorf("couldn't encode transaction Result: %w", err) } if tx.Meta, err = ingestTx.UnsafeMeta.MarshalBinary(); err != nil { - return tx, errors.Wrap(err, "couldn't encode transaction UnsafeMeta") + return tx, fmt.Errorf("couldn't encode transaction UnsafeMeta: %w", err) } if tx.Envelope, err = ingestTx.Envelope.MarshalBinary(); err != nil { - return tx, errors.Wrap(err, "couldn't encode transaction Envelope") + return tx, fmt.Errorf("couldn't encode transaction Envelope: %w", err) } if events, diagErr := ingestTx.GetDiagnosticEvents(); diagErr == nil { tx.Events = make([][]byte, 0, len(events)) for i, event := range events { bytes, ierr := event.MarshalBinary() if ierr != nil { - return tx, errors.Wrapf(ierr, "couldn't encode transaction DiagnosticEvent %d", i) + return tx, fmt.Errorf("couldn't encode transaction DiagnosticEvent %d: %w", i, ierr) } tx.Events = append(tx.Events, bytes) } } else { - return tx, errors.Wrap(diagErr, "couldn't encode transaction DiagnosticEvents") + return tx, fmt.Errorf("couldn't encode transaction DiagnosticEvents: %w", diagErr) } return tx, nil diff --git a/cmd/soroban-rpc/internal/db/transaction_test.go b/cmd/soroban-rpc/internal/db/transaction_test.go index 7257c1e1..a4bf2342 100644 --- a/cmd/soroban-rpc/internal/db/transaction_test.go +++ b/cmd/soroban-rpc/internal/db/transaction_test.go @@ -7,14 +7,14 @@ import ( "testing" "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stellar/go/network" "github.com/stellar/go/support/log" "github.com/stellar/go/xdr" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/daemon/interfaces" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestTransactionNotFound(t *testing.T) { diff --git a/cmd/soroban-rpc/internal/events/cursor.go b/cmd/soroban-rpc/internal/events/cursor.go index 3fbfbecb..8be24efa 100644 --- a/cmd/soroban-rpc/internal/events/cursor.go +++ b/cmd/soroban-rpc/internal/events/cursor.go @@ -48,11 +48,11 @@ func (c *Cursor) UnmarshalJSON(b []byte) error { return err } - if parsed, err := ParseCursor(s); err != nil { + parsed, err := ParseCursor(s) + if err != nil { return err - } else { - *c = parsed } + *c = parsed return nil } @@ -113,8 +113,10 @@ func (c Cursor) Cmp(other Cursor) int { var ( // MinCursor is the smallest possible cursor + //nolint:gochecknoglobals MinCursor = Cursor{} // MaxCursor is the largest possible cursor + //nolint:gochecknoglobals MaxCursor = Cursor{ Ledger: math.MaxUint32, Tx: math.MaxUint32, diff --git a/cmd/soroban-rpc/internal/events/events_test.go b/cmd/soroban-rpc/internal/events/events_test.go index c5fda34c..50012fe9 100644 --- a/cmd/soroban-rpc/internal/events/events_test.go +++ b/cmd/soroban-rpc/internal/events/events_test.go @@ -6,9 +6,10 @@ import ( "github.com/prometheus/client_golang/prometheus" dto "github.com/prometheus/client_model/go" - "github.com/stellar/go/xdr" "github.com/stretchr/testify/require" + "github.com/stellar/go/xdr" + "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/daemon/interfaces" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/ledgerbucketwindow" ) diff --git a/cmd/soroban-rpc/internal/feewindow/feewindow.go b/cmd/soroban-rpc/internal/feewindow/feewindow.go index a65210e3..3d662fbc 100644 --- a/cmd/soroban-rpc/internal/feewindow/feewindow.go +++ b/cmd/soroban-rpc/internal/feewindow/feewindow.go @@ -53,7 +53,7 @@ func (fw *FeeWindow) AppendLedgerFees(fees ledgerbucketwindow.LedgerBucket[[]uin } var allFees []uint64 - for i := uint32(0); i < fw.feesPerLedger.Len(); i++ { + for i := range fw.feesPerLedger.Len() { allFees = append(allFees, fw.feesPerLedger.Get(i).BucketContent...) } fw.distribution = computeFeeDistribution(allFees, fw.feesPerLedger.Len()) @@ -72,7 +72,7 @@ func computeFeeDistribution(fees []uint64, ledgerCount uint32) FeeDistribution { localRepetitions := 0 for i := 1; i < len(fees); i++ { if fees[i] == lastVal { - localRepetitions += 1 + localRepetitions++ continue } @@ -166,7 +166,8 @@ func (fw *FeeWindows) IngestFees(meta xdr.LedgerCloseMeta) error { continue } sorobanFees := tx.UnsafeMeta.V3.SorobanMeta.Ext.V1 - resourceFeeCharged := sorobanFees.TotalNonRefundableResourceFeeCharged + sorobanFees.TotalRefundableResourceFeeCharged + resourceFeeCharged := sorobanFees.TotalNonRefundableResourceFeeCharged + + sorobanFees.TotalRefundableResourceFeeCharged inclusionFee := feeCharged - uint64(resourceFeeCharged) sorobanInclusionFees = append(sorobanInclusionFees, inclusionFee) continue diff --git a/cmd/soroban-rpc/internal/feewindow/feewindow_test.go b/cmd/soroban-rpc/internal/feewindow/feewindow_test.go index 53969ff2..cd28bcad 100644 --- a/cmd/soroban-rpc/internal/feewindow/feewindow_test.go +++ b/cmd/soroban-rpc/internal/feewindow/feewindow_test.go @@ -19,7 +19,8 @@ func TestBasicComputeFeeDistribution(t *testing.T) { }{ {"nil", nil, FeeDistribution{}}, {"empty", []uint64{}, FeeDistribution{}}, - {"one", + { + "one", []uint64{100}, FeeDistribution{ Max: 100, @@ -39,7 +40,8 @@ func TestBasicComputeFeeDistribution(t *testing.T) { FeeCount: 1, }, }, - {"even number of elements: four 100s and six 1000s", + { + "even number of elements: four 100s and six 1000s", []uint64{100, 100, 100, 1000, 100, 1000, 1000, 1000, 1000, 1000}, FeeDistribution{ Max: 1000, @@ -59,7 +61,8 @@ func TestBasicComputeFeeDistribution(t *testing.T) { FeeCount: 10, }, }, - {"odd number of elements: five 100s and six 1000s", + { + "odd number of elements: five 100s and six 1000s", []uint64{100, 100, 100, 1000, 100, 1000, 1000, 1000, 1000, 1000, 100}, FeeDistribution{ Max: 1000, @@ -79,7 +82,8 @@ func TestBasicComputeFeeDistribution(t *testing.T) { FeeCount: 11, }, }, - {"mutiple modes favors the smallest value", + { + "mutiple modes favors the smallest value", []uint64{100, 1000}, FeeDistribution{ Max: 1000, @@ -99,7 +103,8 @@ func TestBasicComputeFeeDistribution(t *testing.T) { FeeCount: 2, }, }, - {"random distribution with a repetition", + { + "random distribution with a repetition", []uint64{515, 245, 245, 530, 221, 262, 927}, FeeDistribution{ Max: 927, @@ -119,7 +124,8 @@ func TestBasicComputeFeeDistribution(t *testing.T) { FeeCount: 7, }, }, - {"random distribution with a repetition of its largest value", + { + "random distribution with a repetition of its largest value", []uint64{515, 245, 530, 221, 262, 927, 927}, FeeDistribution{ Max: 927, @@ -145,7 +151,6 @@ func TestBasicComputeFeeDistribution(t *testing.T) { } func TestComputeFeeDistributionAgainstAlternative(t *testing.T) { - for i := 0; i < 100_000; i++ { fees := generateFees(nil) feesCopy1 := make([]uint64, len(fees)) diff --git a/cmd/soroban-rpc/internal/ingest/service_test.go b/cmd/soroban-rpc/internal/ingest/service_test.go index 32b55327..dbeeb1f6 100644 --- a/cmd/soroban-rpc/internal/ingest/service_test.go +++ b/cmd/soroban-rpc/internal/ingest/service_test.go @@ -21,18 +21,17 @@ import ( "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/feewindow" ) -type ErrorReadWriter struct { -} +type ErrorReadWriter struct{} func (rw *ErrorReadWriter) GetLatestLedgerSequence(ctx context.Context) (uint32, error) { return 0, errors.New("could not get latest ledger sequence") } + func (rw *ErrorReadWriter) NewTx(ctx context.Context) (db.WriteTx, error) { return nil, errors.New("could not create new tx") } func TestRetryRunningIngestion(t *testing.T) { - var retryWg sync.WaitGroup retryWg.Add(1) diff --git a/cmd/soroban-rpc/internal/integrationtest/get_fee_stats_test.go b/cmd/soroban-rpc/internal/integrationtest/get_fee_stats_test.go index 407ebb13..7ec8e132 100644 --- a/cmd/soroban-rpc/internal/integrationtest/get_fee_stats_test.go +++ b/cmd/soroban-rpc/internal/integrationtest/get_fee_stats_test.go @@ -4,11 +4,12 @@ import ( "context" "testing" - "github.com/stellar/go/txnbuild" - "github.com/stellar/go/xdr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/stellar/go/txnbuild" + "github.com/stellar/go/xdr" + "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/integrationtest/infrastructure" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/methods" ) diff --git a/cmd/soroban-rpc/internal/integrationtest/get_transactions_test.go b/cmd/soroban-rpc/internal/integrationtest/get_transactions_test.go index 6af5954f..6c66efb0 100644 --- a/cmd/soroban-rpc/internal/integrationtest/get_transactions_test.go +++ b/cmd/soroban-rpc/internal/integrationtest/get_transactions_test.go @@ -4,9 +4,10 @@ import ( "context" "testing" + "github.com/stretchr/testify/assert" + "github.com/stellar/go/keypair" "github.com/stellar/go/txnbuild" - "github.com/stretchr/testify/assert" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/integrationtest/infrastructure" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/methods" @@ -62,7 +63,7 @@ func TestGetTransactions(t *testing.T) { } err := client.CallResult(context.Background(), "getTransactions", request, &result) assert.NoError(t, err) - assert.Equal(t, len(result.Transactions), 3) + assert.Len(t, result.Transactions, 3) assert.Equal(t, result.Transactions[0].Ledger, ledgers[0]) assert.Equal(t, result.Transactions[1].Ledger, ledgers[1]) assert.Equal(t, result.Transactions[2].Ledger, ledgers[2]) @@ -76,7 +77,7 @@ func TestGetTransactions(t *testing.T) { } err = client.CallResult(context.Background(), "getTransactions", request, &result) assert.NoError(t, err) - assert.Equal(t, len(result.Transactions), 1) + assert.Len(t, result.Transactions, 1) assert.Equal(t, result.Transactions[0].Ledger, ledgers[0]) // Get transactions using previous result's cursor @@ -88,7 +89,7 @@ func TestGetTransactions(t *testing.T) { } err = client.CallResult(context.Background(), "getTransactions", request, &result) assert.NoError(t, err) - assert.Equal(t, len(result.Transactions), 2) + assert.Len(t, result.Transactions, 2) assert.Equal(t, result.Transactions[0].Ledger, ledgers[1]) assert.Equal(t, result.Transactions[1].Ledger, ledgers[2]) } diff --git a/cmd/soroban-rpc/internal/integrationtest/get_version_info_test.go b/cmd/soroban-rpc/internal/integrationtest/get_version_info_test.go index b1bdb858..363f0115 100644 --- a/cmd/soroban-rpc/internal/integrationtest/get_version_info_test.go +++ b/cmd/soroban-rpc/internal/integrationtest/get_version_info_test.go @@ -4,11 +4,10 @@ import ( "context" "testing" - "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/config" - "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/integrationtest/infrastructure" - "github.com/stretchr/testify/assert" + "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/config" + "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/integrationtest/infrastructure" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/methods" ) diff --git a/cmd/soroban-rpc/internal/integrationtest/infrastructure/client.go b/cmd/soroban-rpc/internal/integrationtest/infrastructure/client.go index 4dfdedc0..18a154cb 100644 --- a/cmd/soroban-rpc/internal/integrationtest/infrastructure/client.go +++ b/cmd/soroban-rpc/internal/integrationtest/infrastructure/client.go @@ -7,12 +7,13 @@ import ( "github.com/creachadair/jrpc2" "github.com/creachadair/jrpc2/jhttp" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stellar/go/keypair" "github.com/stellar/go/protocols/stellarcore" "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/methods" ) @@ -161,7 +162,7 @@ func PreflightTransactionParamsLocally(t *testing.T, params txnbuild.Transaction for _, b64 := range response.Results[0].Auth { var a xdr.SorobanAuthorizationEntry err := xdr.SafeUnmarshalBase64(b64, &a) - assert.NoError(t, err) + require.NoError(t, err) auth = append(auth, a) } v.Auth = auth diff --git a/cmd/soroban-rpc/internal/integrationtest/infrastructure/contract.go b/cmd/soroban-rpc/internal/integrationtest/infrastructure/contract.go index 4daa1427..9afd5ae1 100644 --- a/cmd/soroban-rpc/internal/integrationtest/infrastructure/contract.go +++ b/cmd/soroban-rpc/internal/integrationtest/infrastructure/contract.go @@ -7,9 +7,10 @@ import ( "path" "testing" + "github.com/stretchr/testify/require" + "github.com/stellar/go/txnbuild" "github.com/stellar/go/xdr" - "github.com/stretchr/testify/require" ) var testSalt = sha256.Sum256([]byte("a1")) diff --git a/cmd/soroban-rpc/internal/integrationtest/infrastructure/test.go b/cmd/soroban-rpc/internal/integrationtest/infrastructure/test.go index 9279ae77..f8996e12 100644 --- a/cmd/soroban-rpc/internal/integrationtest/infrastructure/test.go +++ b/cmd/soroban-rpc/internal/integrationtest/infrastructure/test.go @@ -210,7 +210,6 @@ func (i *Test) stopContainers() { } downCmd = append(downCmd, "-v") i.runSuccessfulComposeCommand(downCmd...) - } func (i *Test) GetPorts() TestPorts { @@ -224,6 +223,7 @@ func (i *Test) runRPCInContainer() bool { func (i *Test) GetRPCLient() *Client { return i.rpcClient } + func (i *Test) MasterKey() *keypair.Full { return keypair.Root(StandaloneNetworkPassphrase) } @@ -378,7 +378,8 @@ func (i *Test) generateCaptiveCoreCfg(tmplContents []byte, captiveCorePort uint1 } captiveCoreCfgContents := os.Expand(string(tmplContents), mapping) - err := os.WriteFile(filepath.Join(i.rpcConfigFilesDir, captiveCoreConfigFilename), []byte(captiveCoreCfgContents), 0666) + fileName := filepath.Join(i.rpcConfigFilesDir, captiveCoreConfigFilename) + err := os.WriteFile(fileName, []byte(captiveCoreCfgContents), 0o666) require.NoError(i.t, err) } @@ -393,7 +394,7 @@ func (i *Test) generateRPCConfigFile(rpcConfig rpcConfig) { for k, v := range rpcConfig.toMap() { cfgFileContents += fmt.Sprintf("%s=%q\n", k, v) } - err := os.WriteFile(filepath.Join(i.rpcConfigFilesDir, "soroban-rpc.config"), []byte(cfgFileContents), 0666) + err := os.WriteFile(filepath.Join(i.rpcConfigFilesDir, "soroban-rpc.config"), []byte(cfgFileContents), 0o666) require.NoError(i.t, err) } @@ -442,7 +443,7 @@ func (i *Test) createRPCDaemon(c rpcConfig) *daemon.Daemon { } require.NoError(i.t, cfg.SetValues(lookup)) require.NoError(i.t, cfg.Validate()) - cfg.HistoryArchiveUserAgent = fmt.Sprintf("soroban-rpc/%s", config.Version) + cfg.HistoryArchiveUserAgent = "soroban-rpc/" + config.Version logger := supportlog.New() logger.SetOutput(newTestLogWriter(i.t, `rpc="daemon" `)) diff --git a/cmd/soroban-rpc/internal/integrationtest/infrastructure/util.go b/cmd/soroban-rpc/internal/integrationtest/infrastructure/util.go index 3cd791b3..1a34325a 100644 --- a/cmd/soroban-rpc/internal/integrationtest/infrastructure/util.go +++ b/cmd/soroban-rpc/internal/integrationtest/infrastructure/util.go @@ -1,14 +1,13 @@ package infrastructure import ( - "fmt" "net" "path/filepath" "runtime" - "time" - "github.com/stellar/go/txnbuild" "github.com/stretchr/testify/require" + + "github.com/stellar/go/txnbuild" ) //go:noinline @@ -39,14 +38,3 @@ func CreateTransactionParams(account txnbuild.Account, op txnbuild.Operation) tx }, } } - -func isLocalTCPPortOpen(port uint16) bool { - host := fmt.Sprintf("localhost:%d", port) - timeout := time.Second - conn, err := net.DialTimeout("tcp", host, timeout) - if err != nil { - return false - } - conn.Close() - return true -} diff --git a/cmd/soroban-rpc/internal/integrationtest/metrics_test.go b/cmd/soroban-rpc/internal/integrationtest/metrics_test.go index 6d0cf1ae..930a6ed8 100644 --- a/cmd/soroban-rpc/internal/integrationtest/metrics_test.go +++ b/cmd/soroban-rpc/internal/integrationtest/metrics_test.go @@ -9,11 +9,11 @@ import ( "testing" io_prometheus_client "github.com/prometheus/client_model/go" - "github.com/stellar/go/support/errors" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" + "github.com/stellar/go/support/errors" + "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/config" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/integrationtest/infrastructure" ) @@ -43,13 +43,13 @@ func TestMetrics(t *testing.T) { assert.NoError(t, err) var metric *io_prometheus_client.MetricFamily for _, mf := range metricFamilies { - if *mf.Name == "soroban_rpc_log_error_total" { + if mf.GetName() == "soroban_rpc_log_error_total" { metric = mf break } } assert.NotNil(t, metric) - val := metric.Metric[0].Counter.GetValue() + val := metric.GetMetric()[0].GetCounter().GetValue() assert.GreaterOrEqual(t, val, 2.0) } diff --git a/cmd/soroban-rpc/internal/integrationtest/migrate_test.go b/cmd/soroban-rpc/internal/integrationtest/migrate_test.go index dd3c9b9c..750b8b82 100644 --- a/cmd/soroban-rpc/internal/integrationtest/migrate_test.go +++ b/cmd/soroban-rpc/internal/integrationtest/migrate_test.go @@ -72,7 +72,7 @@ func testMigrateFromVersion(t *testing.T, version string) { } err := test.GetRPCLient().CallResult(context.Background(), "getTransactions", getTransactions, &transactionsResult) require.NoError(t, err) - require.Equal(t, 1, len(transactionsResult.Transactions)) + require.Len(t, transactionsResult.Transactions, 1) require.Equal(t, submitTransactionResponse.Ledger, transactionsResult.Transactions[0].Ledger) var eventsResult methods.GetEventsResponse @@ -84,7 +84,7 @@ func testMigrateFromVersion(t *testing.T, version string) { } err = test.GetRPCLient().CallResult(context.Background(), "getEvents", getEventsRequest, &eventsResult) require.NoError(t, err) - require.Equal(t, len(eventsResult.Events), 1) + require.Len(t, eventsResult.Events, 1) require.Equal(t, submitTransactionResponse.Ledger, uint32(eventsResult.Events[0].Ledger)) } diff --git a/cmd/soroban-rpc/internal/integrationtest/transaction_test.go b/cmd/soroban-rpc/internal/integrationtest/transaction_test.go index ddda9f68..37a0c9be 100644 --- a/cmd/soroban-rpc/internal/integrationtest/transaction_test.go +++ b/cmd/soroban-rpc/internal/integrationtest/transaction_test.go @@ -5,11 +5,12 @@ import ( "testing" "github.com/creachadair/jrpc2" + "github.com/stretchr/testify/assert" + "github.com/stellar/go/keypair" proto "github.com/stellar/go/protocols/stellarcore" "github.com/stellar/go/txnbuild" "github.com/stellar/go/xdr" - "github.com/stretchr/testify/assert" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/integrationtest/infrastructure" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/methods" @@ -130,11 +131,10 @@ func TestSendTransactionFailedInsufficientResourceFee(t *testing.T) { assert.NoError(t, xdr.SafeUnmarshalBase64(result.ErrorResultXDR, &errorResult)) assert.Equal(t, xdr.TransactionResultCodeTxSorobanInvalid, errorResult.Result.Code) - assert.Greater(t, len(result.DiagnosticEventsXDR), 0) + assert.NotEmpty(t, result.DiagnosticEventsXDR) var event xdr.DiagnosticEvent err = xdr.SafeUnmarshalBase64(result.DiagnosticEventsXDR[0], &event) assert.NoError(t, err) - } func TestSendTransactionFailedInLedger(t *testing.T) { diff --git a/cmd/soroban-rpc/internal/integrationtest/upgrade_test.go b/cmd/soroban-rpc/internal/integrationtest/upgrade_test.go index 386e95ff..efd26cb2 100644 --- a/cmd/soroban-rpc/internal/integrationtest/upgrade_test.go +++ b/cmd/soroban-rpc/internal/integrationtest/upgrade_test.go @@ -5,9 +5,10 @@ import ( "testing" "time" - "github.com/stellar/go/xdr" "github.com/stretchr/testify/require" + "github.com/stellar/go/xdr" + "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/db" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/integrationtest/infrastructure" ) diff --git a/cmd/soroban-rpc/internal/jsonrpc.go b/cmd/soroban-rpc/internal/jsonrpc.go index 01d0efeb..aede6b93 100644 --- a/cmd/soroban-rpc/internal/jsonrpc.go +++ b/cmd/soroban-rpc/internal/jsonrpc.go @@ -307,7 +307,7 @@ func NewJSONRPCHandler(cfg *config.Config, params HandlerParams) Handler { Namespace: params.Daemon.MetricsNamespace(), Subsystem: "network", Name: "global_request_execution_duration_threshold_limit", Help: "The metric measures the count of requests that surpassed the limit threshold for execution time", }) - var handler http.Handler = network.MakeHTTPRequestDurationLimiter( + handler := network.MakeHTTPRequestDurationLimiter( queueLimitedBridge, cfg.RequestExecutionWarningThreshold, cfg.MaxRequestExecutionDuration, diff --git a/cmd/soroban-rpc/internal/methods/get_events.go b/cmd/soroban-rpc/internal/methods/get_events.go index 6eb705f2..0ce602fc 100644 --- a/cmd/soroban-rpc/internal/methods/get_events.go +++ b/cmd/soroban-rpc/internal/methods/get_events.go @@ -50,7 +50,7 @@ func (e *eventTypeSet) UnmarshalJSON(data []byte) error { } func (e eventTypeSet) MarshalJSON() ([]byte, error) { - var keys []string + keys := make([]string, 0, len(e)) for key := range e { keys = append(keys, key) } @@ -376,7 +376,7 @@ func (h eventsRPCHandler) getEvents(request GetEventsRequest) (GetEventsResponse results = append(results, info) } return GetEventsResponse{ - LatestLedger: uint32(latestLedger), + LatestLedger: latestLedger, Events: results, }, nil } diff --git a/cmd/soroban-rpc/internal/methods/get_latest_ledger_test.go b/cmd/soroban-rpc/internal/methods/get_latest_ledger_test.go index 30e05afa..86a8e48a 100644 --- a/cmd/soroban-rpc/internal/methods/get_latest_ledger_test.go +++ b/cmd/soroban-rpc/internal/methods/get_latest_ledger_test.go @@ -5,9 +5,10 @@ import ( "testing" "github.com/creachadair/jrpc2" - "github.com/stellar/go/xdr" "github.com/stretchr/testify/assert" + "github.com/stellar/go/xdr" + "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/db" ) @@ -17,14 +18,11 @@ const ( expectedLatestLedgerHashBytes byte = 42 ) -type ConstantLedgerEntryReader struct { -} +type ConstantLedgerEntryReader struct{} -type ConstantLedgerEntryReaderTx struct { -} +type ConstantLedgerEntryReaderTx struct{} -type ConstantLedgerReader struct { -} +type ConstantLedgerReader struct{} func (entryReader *ConstantLedgerEntryReader) GetLatestLedgerSequence(ctx context.Context) (uint32, error) { return expectedLatestLedgerSequence, nil diff --git a/cmd/soroban-rpc/internal/methods/get_ledger_entries.go b/cmd/soroban-rpc/internal/methods/get_ledger_entries.go index 551e371a..f7c63b91 100644 --- a/cmd/soroban-rpc/internal/methods/get_ledger_entries.go +++ b/cmd/soroban-rpc/internal/methods/get_ledger_entries.go @@ -12,7 +12,8 @@ import ( "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/db" ) -var ErrLedgerTtlEntriesCannotBeQueriedDirectly = "ledger ttl entries cannot be queried directly" +//nolint:gochecknoglobals +var ErrLedgerTTLEntriesCannotBeQueriedDirectly = "ledger ttl entries cannot be queried directly" type GetLedgerEntriesRequest struct { Keys []string `json:"keys"` @@ -63,7 +64,7 @@ func NewGetLedgerEntriesHandler(logger *log.Entry, ledgerEntryReader db.LedgerEn Infof("could not provide ledger ttl entry %s at index %d from getLedgerEntries request", requestKey, i) return GetLedgerEntriesResponse{}, &jrpc2.Error{ Code: jrpc2.InvalidParams, - Message: ErrLedgerTtlEntriesCannotBeQueriedDirectly, + Message: ErrLedgerTTLEntriesCannotBeQueriedDirectly, } } ledgerKeys = append(ledgerKeys, ledgerKey) @@ -130,7 +131,7 @@ func NewGetLedgerEntriesHandler(logger *log.Entry, ledgerEntryReader db.LedgerEn response := GetLedgerEntriesResponse{ Entries: ledgerEntryResults, - LatestLedger: uint32(latestLedger), + LatestLedger: latestLedger, } return response, nil }) diff --git a/cmd/soroban-rpc/internal/methods/get_ledger_entry.go b/cmd/soroban-rpc/internal/methods/get_ledger_entry.go index a43e4b92..5ffd763a 100644 --- a/cmd/soroban-rpc/internal/methods/get_ledger_entry.go +++ b/cmd/soroban-rpc/internal/methods/get_ledger_entry.go @@ -47,7 +47,7 @@ func NewGetLedgerEntryHandler(logger *log.Entry, ledgerEntryReader db.LedgerEntr if key.Type == xdr.LedgerEntryTypeTtl { return GetLedgerEntryResponse{}, &jrpc2.Error{ Code: jrpc2.InvalidParams, - Message: ErrLedgerTtlEntriesCannotBeQueriedDirectly, + Message: ErrLedgerTTLEntriesCannotBeQueriedDirectly, } } diff --git a/cmd/soroban-rpc/internal/methods/get_transaction_test.go b/cmd/soroban-rpc/internal/methods/get_transaction_test.go index 960adf82..65ceea29 100644 --- a/cmd/soroban-rpc/internal/methods/get_transaction_test.go +++ b/cmd/soroban-rpc/internal/methods/get_transaction_test.go @@ -253,7 +253,6 @@ func txMeta(acctSeq uint32, successful bool) xdr.LedgerCloseMeta { } func txMetaWithEvents(acctSeq uint32, successful bool) xdr.LedgerCloseMeta { - meta := txMeta(acctSeq, successful) contractIDBytes, _ := hex.DecodeString("df06d62447fd25da07c0135eed7557e5a5497ee7d15b7fe345bd47e191d8f577") diff --git a/cmd/soroban-rpc/internal/methods/get_transactions.go b/cmd/soroban-rpc/internal/methods/get_transactions.go index b450622e..6fe48187 100644 --- a/cmd/soroban-rpc/internal/methods/get_transactions.go +++ b/cmd/soroban-rpc/internal/methods/get_transactions.go @@ -3,6 +3,7 @@ package methods import ( "context" "encoding/base64" + "errors" "fmt" "io" "strconv" @@ -11,7 +12,6 @@ import ( "github.com/creachadair/jrpc2/handler" "github.com/stellar/go/ingest" - "github.com/stellar/go/support/errors" "github.com/stellar/go/support/log" "github.com/stellar/go/toid" @@ -38,7 +38,11 @@ func (req GetTransactionsRequest) isValid(maxLimit uint, ledgerRange ledgerbucke return errors.New("startLedger and cursor cannot both be set") } } else if req.StartLedger < ledgerRange.FirstLedger.Sequence || req.StartLedger > ledgerRange.LastLedger.Sequence { - return errors.Errorf("start ledger must be between the oldest ledger: %d and the latest ledger: %d for this rpc instance.", ledgerRange.FirstLedger.Sequence, ledgerRange.LastLedger.Sequence) + return fmt.Errorf( + "start ledger must be between the oldest ledger: %d and the latest ledger: %d for this rpc instance", + ledgerRange.FirstLedger.Sequence, + ledgerRange.LastLedger.Sequence, + ) } if req.Pagination != nil && req.Pagination.Limit > maxLimit { @@ -148,7 +152,7 @@ LedgerLoop: } else if !found { return GetTransactionsResponse{}, &jrpc2.Error{ Code: jrpc2.InvalidParams, - Message: errors.Errorf("ledger close meta not found: %d", ledgerSeq).Error(), + Message: fmt.Sprintf("ledger close meta not found: %d", ledgerSeq), } } diff --git a/cmd/soroban-rpc/internal/methods/get_transactions_test.go b/cmd/soroban-rpc/internal/methods/get_transactions_test.go index f6f7fea2..b02cc750 100644 --- a/cmd/soroban-rpc/internal/methods/get_transactions_test.go +++ b/cmd/soroban-rpc/internal/methods/get_transactions_test.go @@ -2,13 +2,14 @@ package methods import ( "context" + "fmt" "testing" "github.com/creachadair/jrpc2" - "github.com/stellar/go/support/errors" + "github.com/stretchr/testify/assert" + "github.com/stellar/go/toid" "github.com/stellar/go/xdr" - "github.com/stretchr/testify/assert" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/db" ) @@ -71,17 +72,17 @@ func TestGetTransactions_DefaultLimit(t *testing.T) { } func TestGetTransactions_DefaultLimitExceedsLatestLedger(t *testing.T) { - mockDbReader := db.NewMockTransactionStore(NetworkPassphrase) - mockLedgerReader := db.NewMockLedgerReader(mockDbReader) + mockDBReader := db.NewMockTransactionStore(NetworkPassphrase) + mockLedgerReader := db.NewMockLedgerReader(mockDBReader) for i := 1; i <= 3; i++ { meta := createTestLedger(uint32(i)) - err := mockDbReader.InsertTransactions(meta) + err := mockDBReader.InsertTransactions(meta) assert.NoError(t, err) } handler := transactionsRPCHandler{ ledgerReader: mockLedgerReader, - dbReader: mockDbReader, + dbReader: mockDBReader, maxLimit: 100, defaultLimit: 10, networkPassphrase: NetworkPassphrase, @@ -102,21 +103,21 @@ func TestGetTransactions_DefaultLimitExceedsLatestLedger(t *testing.T) { assert.Equal(t, toid.New(3, 2, 1).String(), response.Cursor) // assert transactions result - assert.Equal(t, 6, len(response.Transactions)) + assert.Len(t, response.Transactions, 6) } func TestGetTransactions_CustomLimit(t *testing.T) { - mockDbReader := db.NewMockTransactionStore(NetworkPassphrase) - mockLedgerReader := db.NewMockLedgerReader(mockDbReader) + mockDBReader := db.NewMockTransactionStore(NetworkPassphrase) + mockLedgerReader := db.NewMockLedgerReader(mockDBReader) for i := 1; i <= 10; i++ { meta := createTestLedger(uint32(i)) - err := mockDbReader.InsertTransactions(meta) + err := mockDBReader.InsertTransactions(meta) assert.NoError(t, err) } handler := transactionsRPCHandler{ ledgerReader: mockLedgerReader, - dbReader: mockDbReader, + dbReader: mockDBReader, maxLimit: 100, defaultLimit: 10, networkPassphrase: NetworkPassphrase, @@ -140,23 +141,23 @@ func TestGetTransactions_CustomLimit(t *testing.T) { assert.Equal(t, toid.New(1, 2, 1).String(), response.Cursor) // assert transactions result - assert.Equal(t, 2, len(response.Transactions)) + assert.Len(t, response.Transactions, 2) assert.Equal(t, uint32(1), response.Transactions[0].Ledger) assert.Equal(t, uint32(1), response.Transactions[1].Ledger) } func TestGetTransactions_CustomLimitAndCursor(t *testing.T) { - mockDbReader := db.NewMockTransactionStore(NetworkPassphrase) - mockLedgerReader := db.NewMockLedgerReader(mockDbReader) + mockDBReader := db.NewMockTransactionStore(NetworkPassphrase) + mockLedgerReader := db.NewMockLedgerReader(mockDBReader) for i := 1; i <= 10; i++ { meta := createTestLedger(uint32(i)) - err := mockDbReader.InsertTransactions(meta) + err := mockDBReader.InsertTransactions(meta) assert.NoError(t, err) } handler := transactionsRPCHandler{ ledgerReader: mockLedgerReader, - dbReader: mockDbReader, + dbReader: mockDBReader, maxLimit: 100, defaultLimit: 10, networkPassphrase: NetworkPassphrase, @@ -208,7 +209,10 @@ func TestGetTransactions_InvalidStartLedger(t *testing.T) { } response, err := handler.getTransactionsByLedgerSequence(context.TODO(), request) - expectedErr := errors.Errorf("[%d] start ledger must be between the oldest ledger: 1 and the latest ledger: 3 for this rpc instance.", jrpc2.InvalidRequest) + expectedErr := fmt.Errorf( + "[%d] start ledger must be between the oldest ledger: 1 and the latest ledger: 3 for this rpc instance", + jrpc2.InvalidRequest, + ) assert.Equal(t, expectedErr.Error(), err.Error()) assert.Nil(t, response.Transactions) } @@ -239,7 +243,7 @@ func TestGetTransactions_LedgerNotFound(t *testing.T) { } response, err := handler.getTransactionsByLedgerSequence(context.TODO(), request) - expectedErr := errors.Errorf("[%d] ledger close meta not found: 2", jrpc2.InvalidParams) + expectedErr := fmt.Errorf("[%d] ledger close meta not found: 2", jrpc2.InvalidParams) assert.Equal(t, expectedErr.Error(), err.Error()) assert.Nil(t, response.Transactions) } @@ -269,7 +273,7 @@ func TestGetTransactions_LimitGreaterThanMaxLimit(t *testing.T) { } _, err := handler.getTransactionsByLedgerSequence(context.TODO(), request) - expectedErr := errors.Errorf("[%d] limit must not exceed 100", jrpc2.InvalidRequest) + expectedErr := fmt.Errorf("[%d] limit must not exceed 100", jrpc2.InvalidRequest) assert.Equal(t, expectedErr.Error(), err.Error()) } @@ -297,6 +301,6 @@ func TestGetTransactions_InvalidCursorString(t *testing.T) { } _, err := handler.getTransactionsByLedgerSequence(context.TODO(), request) - expectedErr := errors.Errorf("[%d] strconv.ParseInt: parsing \"abc\": invalid syntax", jrpc2.InvalidParams) + expectedErr := fmt.Errorf("[%d] strconv.ParseInt: parsing \"abc\": invalid syntax", jrpc2.InvalidParams) assert.Equal(t, expectedErr.Error(), err.Error()) } diff --git a/cmd/soroban-rpc/internal/methods/simulate_transaction.go b/cmd/soroban-rpc/internal/methods/simulate_transaction.go index 5b66836c..264f386b 100644 --- a/cmd/soroban-rpc/internal/methods/simulate_transaction.go +++ b/cmd/soroban-rpc/internal/methods/simulate_transaction.go @@ -132,7 +132,7 @@ func (l *LedgerEntryChange) FromXDRDiff(diff preflight.XDRDiff) error { return nil } -// LedgerEntryChange designates a change in a ledger entry. Before and After cannot be be omitted at the same time. +// LedgerEntryChange designates a change in a ledger entry. Before and After cannot be omitted at the same time. // If Before is omitted, it constitutes a creation, if After is omitted, it constitutes a delation. type LedgerEntryChange struct { Type LedgerEntryChangeType `json:"type"` @@ -154,7 +154,7 @@ type SimulateTransactionResponse struct { } type PreflightGetter interface { - GetPreflight(ctx context.Context, params preflight.PreflightGetterParameters) (preflight.Preflight, error) + GetPreflight(ctx context.Context, params preflight.GetterParameters) (preflight.Preflight, error) } // NewSimulateTransactionHandler returns a json rpc handler to run preflight simulations @@ -220,17 +220,17 @@ func NewSimulateTransactionHandler(logger *log.Entry, ledgerEntryReader db.Ledge } } - resource_config := preflight.DefaultResourceConfig() + resourceConfig := preflight.DefaultResourceConfig() if request.ResourceConfig != nil { - resource_config = *request.ResourceConfig + resourceConfig = *request.ResourceConfig } - params := preflight.PreflightGetterParameters{ + params := preflight.GetterParameters{ LedgerEntryReadTx: readTx, BucketListSize: bucketListSize, SourceAccount: sourceAccount, OperationBody: op.Body, Footprint: footprint, - ResourceConfig: resource_config, + ResourceConfig: resourceConfig, ProtocolVersion: protocolVersion, } result, err := getter.GetPreflight(ctx, params) diff --git a/cmd/soroban-rpc/internal/methods/simulate_transaction_test.go b/cmd/soroban-rpc/internal/methods/simulate_transaction_test.go index 0c3184b1..bde1e843 100644 --- a/cmd/soroban-rpc/internal/methods/simulate_transaction_test.go +++ b/cmd/soroban-rpc/internal/methods/simulate_transaction_test.go @@ -5,10 +5,11 @@ import ( "encoding/json" "testing" - "github.com/stellar/go/xdr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/stellar/go/xdr" + "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/preflight" ) diff --git a/cmd/soroban-rpc/internal/network/backlogQ.go b/cmd/soroban-rpc/internal/network/backlogQ.go index b4b2791c..58d789c1 100644 --- a/cmd/soroban-rpc/internal/network/backlogQ.go +++ b/cmd/soroban-rpc/internal/network/backlogQ.go @@ -2,13 +2,13 @@ package network import ( "context" + "fmt" "math" "net/http" "sync/atomic" "github.com/creachadair/jrpc2" - "github.com/stellar/go/support/errors" "github.com/stellar/go/support/log" ) @@ -79,10 +79,8 @@ func (q *backlogHTTPQLimiter) ServeHTTP(res http.ResponseWriter, req *http.Reque } } return - } else { - if q.gauge != nil { - q.gauge.Inc() - } + } else if q.gauge != nil { + q.gauge.Inc() } defer func() { atomic.AddUint64(&q.pending, ^uint64(0)) @@ -110,11 +108,10 @@ func (q *backlogJrpcQLimiter) Handle(ctx context.Context, req *jrpc2.Request) (i q.logger.Infof("Backlog queue limiter reached the queue limit of %d executing concurrent rpc %s requests.", q.limit, req.Method()) } } - return nil, errors.Errorf("rpc queue for %s surpassed queue limit of %d requests", req.Method(), q.limit) - } else { - if q.gauge != nil { - q.gauge.Inc() - } + return nil, fmt.Errorf("rpc queue for %s surpassed queue limit of %d requests", req.Method(), q.limit) + } + if q.gauge != nil { + q.gauge.Inc() } defer func() { diff --git a/cmd/soroban-rpc/internal/network/backlogQ_test.go b/cmd/soroban-rpc/internal/network/backlogQ_test.go index fb738e56..ef35e4d9 100644 --- a/cmd/soroban-rpc/internal/network/backlogQ_test.go +++ b/cmd/soroban-rpc/internal/network/backlogQ_test.go @@ -81,7 +81,7 @@ func TestBacklogQueueLimiter_JrpcNonBlocking(t *testing.T) { for k := requestCount; k > 0; k-- { go func() { _, err := limiter.Handle(context.Background(), nil) - require.Nil(t, err) + require.NoError(t, err) wg.Done() }() } @@ -184,7 +184,7 @@ func TestBacklogQueueLimiter_JrpcBlocking(t *testing.T) { for i := uint64(0); i < queueSize/2; i++ { go func() { _, err := limiter.Handle(context.Background(), &jrpc2.Request{}) - require.Nil(t, err) + require.NoError(t, err) initialGroupBlocking.Done() }() } diff --git a/cmd/soroban-rpc/internal/network/requestdurationlimiter.go b/cmd/soroban-rpc/internal/network/requestdurationlimiter.go index c5af738f..c54350ca 100644 --- a/cmd/soroban-rpc/internal/network/requestdurationlimiter.go +++ b/cmd/soroban-rpc/internal/network/requestdurationlimiter.go @@ -121,6 +121,9 @@ func (w *bufferedResponseWriter) WriteOut(ctx context.Context, rw http.ResponseW } } +// TODO: refactor and simplify this function +// +//nolint:gocognit,cyclop func (q *httpRequestDurationLimiter) ServeHTTP(res http.ResponseWriter, req *http.Request) { if q.limitThreshold == RequestDurationLimiterNoLimit { // if specified max duration, pass-through diff --git a/cmd/soroban-rpc/internal/network/requestdurationlimiter_test.go b/cmd/soroban-rpc/internal/network/requestdurationlimiter_test.go index 9854d57c..b7644880 100644 --- a/cmd/soroban-rpc/internal/network/requestdurationlimiter_test.go +++ b/cmd/soroban-rpc/internal/network/requestdurationlimiter_test.go @@ -8,11 +8,10 @@ import ( "testing" "time" - "github.com/stretchr/testify/require" - "github.com/creachadair/jrpc2" "github.com/creachadair/jrpc2/handler" "github.com/creachadair/jrpc2/jhttp" + "github.com/stretchr/testify/require" ) type TestServerHandlerWrapper struct { @@ -54,7 +53,7 @@ func TestHTTPRequestDurationLimiter_Limiting(t *testing.T) { } n, err := res.Write([]byte{1, 2, 3}) require.Equal(t, 3, n) - require.Nil(t, err) + require.NoError(t, err) }, } warningCounter := TestingCounter{} diff --git a/cmd/soroban-rpc/internal/network/utils_test.go b/cmd/soroban-rpc/internal/network/utils_test.go index 8109a63d..471a2961 100644 --- a/cmd/soroban-rpc/internal/network/utils_test.go +++ b/cmd/soroban-rpc/internal/network/utils_test.go @@ -5,6 +5,7 @@ import ( "sync/atomic" "github.com/sirupsen/logrus" + "github.com/stellar/go/support/log" ) @@ -41,12 +42,15 @@ func makeTestLogCounter() *TestLogsCounter { out.entry.SetLevel(logrus.DebugLevel) return out } + func (te *TestLogsCounter) Entry() *log.Entry { return te.entry } + func (te *TestLogsCounter) Levels() []logrus.Level { return []logrus.Level{logrus.PanicLevel, logrus.FatalLevel, logrus.ErrorLevel, logrus.WarnLevel, logrus.InfoLevel, logrus.DebugLevel, logrus.TraceLevel} } + func (te *TestLogsCounter) Fire(e *logrus.Entry) error { te.writtenLogEntries[e.Level]++ return nil @@ -59,6 +63,7 @@ type TestingResponseWriter struct { func (t *TestingResponseWriter) Header() http.Header { return http.Header{} } + func (t *TestingResponseWriter) Write([]byte) (int, error) { return 0, nil } diff --git a/cmd/soroban-rpc/internal/preflight/pool.go b/cmd/soroban-rpc/internal/preflight/pool.go index c6f8b1fc..71ad82b4 100644 --- a/cmd/soroban-rpc/internal/preflight/pool.go +++ b/cmd/soroban-rpc/internal/preflight/pool.go @@ -23,11 +23,11 @@ type workerResult struct { type workerRequest struct { ctx context.Context - params PreflightParameters + params Parameters resultChan chan<- workerResult } -type PreflightWorkerPool struct { +type WorkerPool struct { ledgerEntryReader db.LedgerEntryReader networkPassphrase string enableDebug bool @@ -41,16 +41,26 @@ type PreflightWorkerPool struct { wg sync.WaitGroup } -func NewPreflightWorkerPool(daemon interfaces.Daemon, workerCount uint, jobQueueCapacity uint, enableDebug bool, ledgerEntryReader db.LedgerEntryReader, networkPassphrase string, logger *log.Entry) *PreflightWorkerPool { - preflightWP := PreflightWorkerPool{ - ledgerEntryReader: ledgerEntryReader, - networkPassphrase: networkPassphrase, - enableDebug: enableDebug, - logger: logger, - requestChan: make(chan workerRequest, jobQueueCapacity), +type WorkerPoolConfig struct { + Daemon interfaces.Daemon + WorkerCount uint + JobQueueCapacity uint + EnableDebug bool + LedgerEntryReader db.LedgerEntryReader + NetworkPassphrase string + Logger *log.Entry +} + +func NewPreflightWorkerPool(cfg WorkerPoolConfig) *WorkerPool { + preflightWP := WorkerPool{ + ledgerEntryReader: cfg.LedgerEntryReader, + networkPassphrase: cfg.NetworkPassphrase, + enableDebug: cfg.EnableDebug, + logger: cfg.Logger, + requestChan: make(chan workerRequest, cfg.JobQueueCapacity), } requestQueueMetric := prometheus.NewGaugeFunc(prometheus.GaugeOpts{ - Namespace: daemon.MetricsNamespace(), + Namespace: cfg.Daemon.MetricsNamespace(), Subsystem: "preflight_pool", Name: "queue_length", Help: "number of preflight requests in the queue", @@ -58,46 +68,46 @@ func NewPreflightWorkerPool(daemon interfaces.Daemon, workerCount uint, jobQueue return float64(len(preflightWP.requestChan)) }) preflightWP.concurrentRequestsMetric = prometheus.NewGauge(prometheus.GaugeOpts{ - Namespace: daemon.MetricsNamespace(), + Namespace: cfg.Daemon.MetricsNamespace(), Subsystem: "preflight_pool", Name: "concurrent_requests", Help: "number of preflight requests currently running", }) preflightWP.errorFullCounter = prometheus.NewCounter(prometheus.CounterOpts{ - Namespace: daemon.MetricsNamespace(), + Namespace: cfg.Daemon.MetricsNamespace(), Subsystem: "preflight_pool", Name: "queue_full_errors", Help: "number of preflight full queue errors", }) preflightWP.durationMetric = prometheus.NewSummaryVec(prometheus.SummaryOpts{ - Namespace: daemon.MetricsNamespace(), + Namespace: cfg.Daemon.MetricsNamespace(), Subsystem: "preflight_pool", Name: "request_ledger_get_duration_seconds", Help: "preflight request duration broken down by status", Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, }, []string{"status", "type"}) preflightWP.ledgerEntriesFetchedMetric = prometheus.NewSummary(prometheus.SummaryOpts{ - Namespace: daemon.MetricsNamespace(), + Namespace: cfg.Daemon.MetricsNamespace(), Subsystem: "preflight_pool", Name: "request_ledger_entries_fetched", Help: "ledger entries fetched by simulate transaction calls", Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, }) - daemon.MetricsRegistry().MustRegister( + cfg.Daemon.MetricsRegistry().MustRegister( requestQueueMetric, preflightWP.concurrentRequestsMetric, preflightWP.errorFullCounter, preflightWP.durationMetric, preflightWP.ledgerEntriesFetchedMetric, ) - for i := uint(0); i < workerCount; i++ { + for range cfg.WorkerCount { preflightWP.wg.Add(1) go preflightWP.work() } return &preflightWP } -func (pwp *PreflightWorkerPool) work() { +func (pwp *WorkerPool) work() { defer pwp.wg.Done() for request := range pwp.requestChan { pwp.concurrentRequestsMetric.Inc() @@ -115,7 +125,7 @@ func (pwp *PreflightWorkerPool) work() { } } -func (pwp *PreflightWorkerPool) Close() { +func (pwp *WorkerPool) Close() { if !pwp.isClosed.CompareAndSwap(false, true) { // it was already closed return @@ -124,7 +134,7 @@ func (pwp *PreflightWorkerPool) Close() { pwp.wg.Wait() } -var PreflightQueueFullErr = errors.New("preflight queue full") +var ErrPreflightQueueFull = errors.New("preflight queue full") type metricsLedgerEntryWrapper struct { db.LedgerEntryReadTx @@ -140,14 +150,14 @@ func (m *metricsLedgerEntryWrapper) GetLedgerEntries(keys ...xdr.LedgerKey) ([]d return entries, err } -func (pwp *PreflightWorkerPool) GetPreflight(ctx context.Context, params PreflightGetterParameters) (Preflight, error) { +func (pwp *WorkerPool) GetPreflight(ctx context.Context, params GetterParameters) (Preflight, error) { if pwp.isClosed.Load() { return Preflight{}, errors.New("preflight worker pool is closed") } wrappedTx := metricsLedgerEntryWrapper{ LedgerEntryReadTx: params.LedgerEntryReadTx, } - preflightParams := PreflightParameters{ + preflightParams := Parameters{ Logger: pwp.logger, SourceAccount: params.SourceAccount, OpBody: params.OperationBody, @@ -178,6 +188,6 @@ func (pwp *PreflightWorkerPool) GetPreflight(ctx context.Context, params Preflig return Preflight{}, ctx.Err() default: pwp.errorFullCounter.Inc() - return Preflight{}, PreflightQueueFullErr + return Preflight{}, ErrPreflightQueueFull } } diff --git a/cmd/soroban-rpc/internal/preflight/preflight.go b/cmd/soroban-rpc/internal/preflight/preflight.go index b79be958..2c4485d8 100644 --- a/cmd/soroban-rpc/internal/preflight/preflight.go +++ b/cmd/soroban-rpc/internal/preflight/preflight.go @@ -87,7 +87,7 @@ func DefaultResourceConfig() ResourceConfig { } } -type PreflightGetterParameters struct { +type GetterParameters struct { LedgerEntryReadTx db.LedgerEntryReadTx BucketListSize uint64 SourceAccount xdr.AccountId @@ -97,7 +97,7 @@ type PreflightGetterParameters struct { ProtocolVersion uint32 } -type PreflightParameters struct { +type Parameters struct { Logger *log.Entry SourceAccount xdr.AccountId OpBody xdr.OperationBody @@ -159,18 +159,18 @@ func GoXDRDiffVector(xdrDiffVector C.xdr_diff_vector_t) []XDRDiff { return result } -func GetPreflight(_ context.Context, params PreflightParameters) (Preflight, error) { +func GetPreflight(_ context.Context, params Parameters) (Preflight, error) { switch params.OpBody.Type { case xdr.OperationTypeInvokeHostFunction: return getInvokeHostFunctionPreflight(params) case xdr.OperationTypeExtendFootprintTtl, xdr.OperationTypeRestoreFootprint: - return getFootprintTtlPreflight(params) + return getFootprintTTLPreflight(params) default: return Preflight{}, fmt.Errorf("unsupported operation type: %s", params.OpBody.Type.String()) } } -func getLedgerInfo(params PreflightParameters) (C.ledger_info_t, error) { +func getLedgerInfo(params Parameters) (C.ledger_info_t, error) { simulationLedgerSeq, err := getSimulationLedgerSeq(params.LedgerEntryReadTx) if err != nil { return C.ledger_info_t{}, err @@ -187,7 +187,7 @@ func getLedgerInfo(params PreflightParameters) (C.ledger_info_t, error) { return ledgerInfo, nil } -func getFootprintTtlPreflight(params PreflightParameters) (Preflight, error) { +func getFootprintTTLPreflight(params Parameters) (Preflight, error) { opBodyXDR, err := params.OpBody.MarshalBinary() if err != nil { return Preflight{}, err @@ -231,7 +231,7 @@ func getSimulationLedgerSeq(readTx db.LedgerEntryReadTx) (uint32, error) { return sequenceNumber, nil } -func getInvokeHostFunctionPreflight(params PreflightParameters) (Preflight, error) { +func getInvokeHostFunctionPreflight(params Parameters) (Preflight, error) { invokeHostFunctionXDR, err := params.OpBody.MustInvokeHostFunctionOp().MarshalBinary() if err != nil { return Preflight{}, err diff --git a/cmd/soroban-rpc/internal/preflight/preflight_test.go b/cmd/soroban-rpc/internal/preflight/preflight_test.go index 4e361605..5de512ca 100644 --- a/cmd/soroban-rpc/internal/preflight/preflight_test.go +++ b/cmd/soroban-rpc/internal/preflight/preflight_test.go @@ -8,17 +8,20 @@ import ( "runtime" "testing" + "github.com/stretchr/testify/require" + "github.com/stellar/go/network" "github.com/stellar/go/support/log" "github.com/stellar/go/xdr" - "github.com/stretchr/testify/require" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/daemon/interfaces" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/db" ) -var mockContractID = xdr.Hash{0xa, 0xb, 0xc} -var mockContractHash = xdr.Hash{0xd, 0xe, 0xf} +var ( + mockContractID = xdr.Hash{0xa, 0xb, 0xc} + mockContractHash = xdr.Hash{0xd, 0xe, 0xf} +) var contractCostParams = func() *xdr.ContractCostParams { var result xdr.ContractCostParams @@ -321,7 +324,7 @@ type preflightParametersDBConfig struct { disableCache bool } -func getPreflightParameters(t testing.TB, dbConfig *preflightParametersDBConfig) PreflightParameters { +func getPreflightParameters(t testing.TB, dbConfig *preflightParametersDBConfig) Parameters { var ledgerEntryReadTx db.LedgerEntryReadTx if dbConfig != nil { entryReader := db.NewLedgerEntryReader(dbConfig.dbInstance) @@ -338,11 +341,12 @@ func getPreflightParameters(t testing.TB, dbConfig *preflightParametersDBConfig) require.NoError(t, err) } argSymbol := xdr.ScSymbol("world") - params := PreflightParameters{ + params := Parameters{ EnableDebug: true, Logger: log.New(), SourceAccount: xdr.MustAddress("GBRPYHIL2CI3FNQ4BXLFMNDLFJUNPU2HY3ZMFSHONUCEOASW7QC7OX2H"), - OpBody: xdr.OperationBody{Type: xdr.OperationTypeInvokeHostFunction, + OpBody: xdr.OperationBody{ + Type: xdr.OperationTypeInvokeHostFunction, InvokeHostFunctionOp: &xdr.InvokeHostFunctionOp{ HostFunction: xdr.HostFunction{ Type: xdr.HostFunctionTypeHostFunctionTypeInvokeContract, @@ -360,7 +364,8 @@ func getPreflightParameters(t testing.TB, dbConfig *preflightParametersDBConfig) }, }, }, - }}, + }, + }, NetworkPassphrase: "foo", LedgerEntryReadTx: ledgerEntryReadTx, BucketListSize: 200, diff --git a/cmd/soroban-rpc/internal/util/panicgroup_test.go b/cmd/soroban-rpc/internal/util/panicgroup_test.go index 63c42206..64ed7a16 100644 --- a/cmd/soroban-rpc/internal/util/panicgroup_test.go +++ b/cmd/soroban-rpc/internal/util/panicgroup_test.go @@ -7,8 +7,9 @@ import ( "time" "github.com/sirupsen/logrus" - "github.com/stellar/go/support/log" "github.com/stretchr/testify/require" + + "github.com/stellar/go/support/log" ) func TestTrivialPanicGroup(t *testing.T) { @@ -34,18 +35,22 @@ func makeTestLogCounter() *TestLogsCounter { out.entry.SetLevel(logrus.DebugLevel) return out } + func (te *TestLogsCounter) Entry() *log.Entry { return te.entry } + func (te *TestLogsCounter) Levels() []logrus.Level { return []logrus.Level{logrus.PanicLevel, logrus.FatalLevel, logrus.ErrorLevel, logrus.WarnLevel, logrus.InfoLevel, logrus.DebugLevel, logrus.TraceLevel} } + func (te *TestLogsCounter) Fire(e *logrus.Entry) error { te.mu.Lock() defer te.mu.Unlock() te.writtenLogEntries[e.Level]++ return nil } + func (te *TestLogsCounter) GetLevel(i int) int { te.mu.Lock() defer te.mu.Unlock() diff --git a/cmd/soroban-rpc/main.go b/cmd/soroban-rpc/main.go index 002a0ee8..84fa9116 100644 --- a/cmd/soroban-rpc/main.go +++ b/cmd/soroban-rpc/main.go @@ -49,8 +49,10 @@ func main() { if branch == "main" { branch = "" } + //nolint:forbidigo fmt.Printf("soroban-rpc %s (%s) %s\n", config.Version, config.CommitHash, branch) } + //nolint:forbidigo fmt.Printf("stellar-xdr %s\n", goxdr.CommitHash) }, } From eb7cb8aa8ec4c4129bcb5dc0dfc8c6f963f967a5 Mon Sep 17 00:00:00 2001 From: Alfonso Acosta Date: Tue, 25 Jun 2024 18:49:32 +0200 Subject: [PATCH 5/6] Disable paralleltest linter (#232) --- .golangci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.golangci.yml b/.golangci.yml index dcdfcad4..8425f3d3 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -108,6 +108,7 @@ linters: # TODO: ireturn: consider enabling it later on - ireturn - godot + - paralleltest presets: [ ] fast: false From ef78ce0da6e39b333bc9b95d460005be68d8e62f Mon Sep 17 00:00:00 2001 From: Alfonso Acosta Date: Thu, 27 Jun 2024 16:19:15 +0200 Subject: [PATCH 6/6] Unify transaction and event retention windows (#234) * Unify transaction and event retention windows Use a new, `unified history-retention-window` flag and mark the event/transaction window configuration parameters as deprecated. Until we remove the event/transaction flag, `history-retention-window` will be initialized to the maximum of the three. * Appease the linter --- cmd/soroban-rpc/internal/config/main.go | 9 +++++ cmd/soroban-rpc/internal/config/main_test.go | 6 +-- cmd/soroban-rpc/internal/config/options.go | 39 +++++++++++++------ cmd/soroban-rpc/internal/config/toml_test.go | 5 ++- cmd/soroban-rpc/internal/daemon/daemon.go | 15 +------ cmd/soroban-rpc/internal/db/migration.go | 7 +++- .../internal/integrationtest/health_test.go | 4 +- .../integrationtest/infrastructure/test.go | 5 +-- cmd/soroban-rpc/internal/jsonrpc.go | 5 +-- .../ledgerbucketwindow/ledgerbucketwindow.go | 10 ----- cmd/soroban-rpc/main.go | 1 - 11 files changed, 54 insertions(+), 52 deletions(-) diff --git a/cmd/soroban-rpc/internal/config/main.go b/cmd/soroban-rpc/internal/config/main.go index 1321feb6..4282d824 100644 --- a/cmd/soroban-rpc/internal/config/main.go +++ b/cmd/soroban-rpc/internal/config/main.go @@ -41,6 +41,7 @@ type Config struct { PreflightWorkerQueueSize uint PreflightEnableDebug bool SQLiteDBPath string + HistoryRetentionWindow uint32 TransactionLedgerRetentionWindow uint32 SorobanFeeStatsLedgerRetentionWindow uint32 ClassicFeeStatsLedgerRetentionWindow uint32 @@ -114,6 +115,13 @@ func (cfg *Config) SetValues(lookupEnv func(string) (string, bool)) error { } } + // Set to the maximum as a compromise until we deprecate the transaction/event flags + cfg.HistoryRetentionWindow = max( + cfg.HistoryRetentionWindow, + cfg.EventLedgerRetentionWindow, + cfg.TransactionLedgerRetentionWindow, + ) + return nil } @@ -126,6 +134,7 @@ func (cfg *Config) loadDefaults() error { } } } + cfg.HistoryArchiveUserAgent = "soroban-rpc/" + Version return nil } diff --git a/cmd/soroban-rpc/internal/config/main_test.go b/cmd/soroban-rpc/internal/config/main_test.go index df006b7e..c510c1bd 100644 --- a/cmd/soroban-rpc/internal/config/main_test.go +++ b/cmd/soroban-rpc/internal/config/main_test.go @@ -52,11 +52,9 @@ func TestConfigLoadDefaults(t *testing.T) { } func TestConfigExtendedUserAgent(t *testing.T) { - cfg := Config{ - HistoryArchiveUserAgent: "Test", - } + var cfg Config require.NoError(t, cfg.loadDefaults()) - assert.Equal(t, "Test/123", cfg.ExtendedUserAgent("123")) + assert.Equal(t, "soroban-rpc/0.0.0/123", cfg.ExtendedUserAgent("123")) } func TestConfigLoadFlagsDefaultValuesOverrideExisting(t *testing.T) { diff --git a/cmd/soroban-rpc/internal/config/options.go b/cmd/soroban-rpc/internal/config/options.go index e4838ab5..9d14084a 100644 --- a/cmd/soroban-rpc/internal/config/options.go +++ b/cmd/soroban-rpc/internal/config/options.go @@ -13,11 +13,14 @@ import ( "github.com/stellar/go/network" "github.com/stellar/go/support/strutils" - - "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/ledgerbucketwindow" ) -const defaultHTTPEndpoint = "localhost:8000" +const ( + // OneDayOfLedgers is (roughly) a 24 hour window of ledgers. + OneDayOfLedgers = 17280 + + defaultHTTPEndpoint = "localhost:8000" +) // TODO: refactor and remove the linter exceptions // @@ -159,7 +162,7 @@ func (cfg *Config) options() Options { if v == "" || v == "." { cwd, err := os.Getwd() if err != nil { - return fmt.Errorf("unable to determine the current directory: %s", err) + return fmt.Errorf("unable to determine the current directory: %w", err) } v = cwd } @@ -168,7 +171,7 @@ func (cfg *Config) options() Options { case nil: cwd, err := os.Getwd() if err != nil { - return fmt.Errorf("unable to determine the current directory: %s", err) + return fmt.Errorf("unable to determine the current directory: %w", err) } cfg.CaptiveCoreStoragePath = cwd return nil @@ -212,24 +215,36 @@ func (cfg *Config) options() Options { ConfigKey: &cfg.CheckpointFrequency, DefaultValue: uint32(64), }, + { + Name: "history-retention-window", + Usage: fmt.Sprintf( + "configures history retention window for transactions and events, expressed in number of ledgers,"+ + " the default value is %d which corresponds to about 24 hours of history", + OneDayOfLedgers), + ConfigKey: &cfg.HistoryRetentionWindow, + DefaultValue: uint32(OneDayOfLedgers), + Validate: positive, + }, + // TODO: remove { Name: "event-retention-window", Usage: fmt.Sprintf( - "configures the event retention window expressed in number of ledgers,"+ + "(Deprecated, overidden by history-retention-window) configures the event retention window expressed in number of ledgers,"+ " the default value is %d which corresponds to about 24 hours of history", - ledgerbucketwindow.DefaultEventLedgerRetentionWindow), + OneDayOfLedgers), ConfigKey: &cfg.EventLedgerRetentionWindow, - DefaultValue: uint32(ledgerbucketwindow.DefaultEventLedgerRetentionWindow), + DefaultValue: uint32(OneDayOfLedgers), Validate: positive, }, + // TODO: remove { Name: "transaction-retention-window", Usage: fmt.Sprintf( - "configures the transaction retention window expressed in number of ledgers,"+ + "(Deprecated, overidden by history-retention-window) configures the transaction retention window expressed in number of ledgers,"+ " the default value is %d which corresponds to about 24 hours of history", - ledgerbucketwindow.OneDayOfLedgers), + OneDayOfLedgers), ConfigKey: &cfg.TransactionLedgerRetentionWindow, - DefaultValue: uint32(ledgerbucketwindow.OneDayOfLedgers), + DefaultValue: uint32(OneDayOfLedgers), Validate: positive, }, { @@ -504,7 +519,7 @@ func required(option *Option) error { } } - waysToSet := []string{} + var waysToSet []string if option.Name != "" && option.Name != "-" { waysToSet = append(waysToSet, fmt.Sprintf("specify --%s on the command line", option.Name)) } diff --git a/cmd/soroban-rpc/internal/config/toml_test.go b/cmd/soroban-rpc/internal/config/toml_test.go index 0b438996..ae762567 100644 --- a/cmd/soroban-rpc/internal/config/toml_test.go +++ b/cmd/soroban-rpc/internal/config/toml_test.go @@ -92,7 +92,10 @@ func TestBasicTomlWriting(t *testing.T) { // Note the newline at char 80. This also checks it adds a space after the // comment when outputting multi-line comments, which go-toml does *not* do // by default. - assert.Contains(t, out, "# configures the event retention window expressed in number of ledgers, the\n# default value is 17280 which corresponds to about 24 hours of history") + assert.Contains(t, out, + `# (Deprecated, overidden by history-retention-window) configures the event +# retention window expressed in number of ledgers, the default value is 17280 +# which corresponds to about 24 hours of history`) } func TestRoundTrip(t *testing.T) { diff --git a/cmd/soroban-rpc/internal/daemon/daemon.go b/cmd/soroban-rpc/internal/daemon/daemon.go index 5ca3004b..ab8ec8a0 100644 --- a/cmd/soroban-rpc/internal/daemon/daemon.go +++ b/cmd/soroban-rpc/internal/daemon/daemon.go @@ -21,7 +21,6 @@ import ( "github.com/stellar/go/ingest/ledgerbackend" supporthttp "github.com/stellar/go/support/http" supportlog "github.com/stellar/go/support/log" - "github.com/stellar/go/support/ordered" "github.com/stellar/go/support/storage" "github.com/stellar/go/xdr" @@ -31,7 +30,6 @@ import ( "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/ingest" - "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/ledgerbucketwindow" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/preflight" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/util" ) @@ -207,15 +205,6 @@ func MustNew(cfg *config.Config, logger *supportlog.Entry) *Daemon { logger.WithError(err).Error("could not run ingestion. Retrying") } - // Take the larger of (event retention, tx retention) and then the smaller - // of (tx retention, default event retention) if event retention wasn't - // specified, for some reason...? - maxRetentionWindow := ordered.Max(cfg.EventLedgerRetentionWindow, cfg.TransactionLedgerRetentionWindow) - if cfg.EventLedgerRetentionWindow <= 0 { - maxRetentionWindow = ordered.Min( - maxRetentionWindow, - ledgerbucketwindow.DefaultEventLedgerRetentionWindow) - } ingestService := ingest.NewService(ingest.Config{ Logger: logger, DB: db.NewReadWriter( @@ -223,7 +212,7 @@ func MustNew(cfg *config.Config, logger *supportlog.Entry) *Daemon { dbConn, daemon, maxLedgerEntryWriteBatchSize, - maxRetentionWindow, + cfg.HistoryRetentionWindow, cfg.NetworkPassphrase, ), EventStore: eventStore, @@ -305,7 +294,7 @@ func (d *Daemon) mustInitializeStorage(cfg *config.Config) (*feewindow.FeeWindow eventStore := events.NewMemoryStore( d, cfg.NetworkPassphrase, - cfg.EventLedgerRetentionWindow, + cfg.HistoryRetentionWindow, ) feewindows := feewindow.NewFeeWindows(cfg.ClassicFeeStatsLedgerRetentionWindow, cfg.SorobanFeeStatsLedgerRetentionWindow, cfg.NetworkPassphrase) diff --git a/cmd/soroban-rpc/internal/db/migration.go b/cmd/soroban-rpc/internal/db/migration.go index 74a88f87..dbe07ab5 100644 --- a/cmd/soroban-rpc/internal/db/migration.go +++ b/cmd/soroban-rpc/internal/db/migration.go @@ -183,7 +183,12 @@ func (g *guardedMigration) Rollback(ctx context.Context) error { func BuildMigrations(ctx context.Context, logger *log.Entry, db *DB, cfg *config.Config) (Migration, error) { migrationName := "TransactionsTable" - factory := newTransactionTableMigration(ctx, logger.WithField("migration", migrationName), cfg.TransactionLedgerRetentionWindow, cfg.NetworkPassphrase) + factory := newTransactionTableMigration( + ctx, + logger.WithField("migration", migrationName), + cfg.HistoryRetentionWindow, + cfg.NetworkPassphrase, + ) m, err := newGuardedDataMigration(ctx, migrationName, factory, db) if err != nil { return nil, fmt.Errorf("creating guarded transaction migration: %w", err) diff --git a/cmd/soroban-rpc/internal/integrationtest/health_test.go b/cmd/soroban-rpc/internal/integrationtest/health_test.go index 2fe9ab86..c06639cd 100644 --- a/cmd/soroban-rpc/internal/integrationtest/health_test.go +++ b/cmd/soroban-rpc/internal/integrationtest/health_test.go @@ -6,8 +6,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/config" "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/integrationtest/infrastructure" - "github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/ledgerbucketwindow" ) func TestHealth(t *testing.T) { @@ -15,7 +15,7 @@ func TestHealth(t *testing.T) { result, err := test.GetRPCHealth() require.NoError(t, err) assert.Equal(t, "healthy", result.Status) - assert.Equal(t, uint32(ledgerbucketwindow.OneDayOfLedgers), result.LedgerRetentionWindow) + assert.Equal(t, uint32(config.OneDayOfLedgers), result.LedgerRetentionWindow) assert.Greater(t, result.OldestLedger, uint32(0)) assert.Greater(t, result.LatestLedger, uint32(0)) assert.GreaterOrEqual(t, result.LatestLedger, result.OldestLedger) diff --git a/cmd/soroban-rpc/internal/integrationtest/infrastructure/test.go b/cmd/soroban-rpc/internal/integrationtest/infrastructure/test.go index f8996e12..c839a553 100644 --- a/cmd/soroban-rpc/internal/integrationtest/infrastructure/test.go +++ b/cmd/soroban-rpc/internal/integrationtest/infrastructure/test.go @@ -30,7 +30,6 @@ import ( "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" ) @@ -321,8 +320,7 @@ func (vars rpcConfig) toMap() map[string]string { "LOG_LEVEL": "debug", "DB_PATH": vars.sqlitePath, "INGESTION_TIMEOUT": "10m", - "EVENT_LEDGER_RETENTION_WINDOW": strconv.Itoa(ledgerbucketwindow.OneDayOfLedgers), - "TRANSACTION_RETENTION_WINDOW": strconv.Itoa(ledgerbucketwindow.OneDayOfLedgers), + "HISTORY_RETENTION_WINDOW": strconv.Itoa(config.OneDayOfLedgers), "CHECKPOINT_FREQUENCY": strconv.Itoa(checkpointFrequency), "MAX_HEALTHY_LEDGER_LATENCY": "10s", "PREFLIGHT_ENABLE_DEBUG": "true", @@ -443,7 +441,6 @@ func (i *Test) createRPCDaemon(c rpcConfig) *daemon.Daemon { } require.NoError(i.t, cfg.SetValues(lookup)) require.NoError(i.t, cfg.Validate()) - cfg.HistoryArchiveUserAgent = "soroban-rpc/" + config.Version logger := supportlog.New() logger.SetOutput(newTestLogWriter(i.t, `rpc="daemon" `)) diff --git a/cmd/soroban-rpc/internal/jsonrpc.go b/cmd/soroban-rpc/internal/jsonrpc.go index aede6b93..9236a4a4 100644 --- a/cmd/soroban-rpc/internal/jsonrpc.go +++ b/cmd/soroban-rpc/internal/jsonrpc.go @@ -137,10 +137,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. - retentionWindow := cfg.TransactionLedgerRetentionWindow + retentionWindow := cfg.HistoryRetentionWindow handlers := []struct { methodName string diff --git a/cmd/soroban-rpc/internal/ledgerbucketwindow/ledgerbucketwindow.go b/cmd/soroban-rpc/internal/ledgerbucketwindow/ledgerbucketwindow.go index fe0eb58e..0f3ca5e2 100644 --- a/cmd/soroban-rpc/internal/ledgerbucketwindow/ledgerbucketwindow.go +++ b/cmd/soroban-rpc/internal/ledgerbucketwindow/ledgerbucketwindow.go @@ -20,18 +20,8 @@ type LedgerBucket[T any] struct { BucketContent T } -// OneDayOfLedgers is (roughly) a 24 hour window of ledgers. -const OneDayOfLedgers = 17280 - -// DefaultEventLedgerRetentionWindow represents the max number of ledgers we -// would like to keep an incoming event in memory. -const DefaultEventLedgerRetentionWindow = OneDayOfLedgers - // NewLedgerBucketWindow creates a new LedgerBucketWindow func NewLedgerBucketWindow[T any](retentionWindow uint32) *LedgerBucketWindow[T] { - if retentionWindow == 0 { - retentionWindow = DefaultEventLedgerRetentionWindow - } return &LedgerBucketWindow[T]{ buckets: make([]LedgerBucket[T], 0, retentionWindow), } diff --git a/cmd/soroban-rpc/main.go b/cmd/soroban-rpc/main.go index 84fa9116..e2150451 100644 --- a/cmd/soroban-rpc/main.go +++ b/cmd/soroban-rpc/main.go @@ -28,7 +28,6 @@ func main() { fmt.Fprintln(os.Stderr, err) os.Exit(1) } - cfg.HistoryArchiveUserAgent = "soroban-rpc/" + config.Version daemon.MustNew(&cfg, supportlog.New()).Run() }, }