From 8c50fc98f2c7984c19a280c3c6e3ab3e2335f72c Mon Sep 17 00:00:00 2001 From: Justin Tieri <37750742+jtieri@users.noreply.github.com> Date: Wed, 21 Aug 2024 13:51:24 -0500 Subject: [PATCH 01/14] ci: revise golangci-lint settings --- .github/workflows/lint.yml | 27 +++++++++++---- .golangci.yml | 67 ++++++++++++++++++++++++++++++-------- 2 files changed, 73 insertions(+), 21 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index bacb81e7..47c14445 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,4 +1,6 @@ -name: golangci-lint +# Lint the entire golang project. This workflow relies on the +# '.golangci.yml' file for its configuration settings. +name: Lint on: push: tags: @@ -7,15 +9,26 @@ on: - master - main pull_request: + +permissions: + contents: read + +env: + GO_VERSION: 1.21 + jobs: golangci: - name: lint + name: golangci-lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + + - uses: actions/checkout@v4 + - name: golangci-lint - uses: golangci/golangci-lint-action@v3 + uses: golangci/golangci-lint-action@v6.1.0 with: - version: latest - only-new-issues: true - args: --timeout=3m + version: v1.57.2 + args: --timeout 15m \ No newline at end of file diff --git a/.golangci.yml b/.golangci.yml index 8fe7a04a..c18569cf 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,29 +1,70 @@ +run: + timeout: 10m + tests: true + +# These linter checks can be modified on a per project basis. +# Simply remove them from the enable list to disable them. linters: + disable-all: true enable: + - asciicheck + - bidichk - bodyclose - - dogsled + - decorder + - dupl + - dupword + - errcheck + - errchkjson + - errname + - exhaustive + - exportloopref + - forbidigo + - gci - goconst - gocritic - - gofmt - - goimports + - godot + - gofumpt - gosec - gosimple + - gosmopolitan - govet - - importas + - grouper - ineffassign - - lll + - loggercheck - misspell - - nakedret - - prealloc - - revive + - nilerr + - nilnil + - noctx - staticcheck - stylecheck + - testifylint + - thelper + - tparallel - typecheck - unconvert + - unparam - unused - - nolintlint + - usestdlibvars + - wastedassign + - whitespace linters-settings: + gci: + custom-order: true + sections: + - standard # Standard section: captures all standard packages. + - default # Default section: contains all imports that could not be matched to another section type. + - blank # blank imports + - dot # dot imports + - prefix(cosmossdk.io) + - prefix(github.com/cosmos) + - prefix(github.com/cosmos/cosmos-sdk) + - prefix(github.com/cometbft/cometbft) + # TODO: Replace below with '- prefix()' + - prefix(github.com/strangelove-ventures/horcrux) + gosec: + excludes: + - G404 # disables checks on insecure random number source dogsled: max-blank-identifiers: 3 importas: @@ -99,8 +140,6 @@ linters-settings: alias: boltdb - pkg: math/rand alias: mrand - maligned: - suggest-new: true - govet: - misspell: - locale: US + +issues: + max-issues-per-linter: 0 From 557bbd4aa8e168fff47e84d57465671ef3bc6b34 Mon Sep 17 00:00:00 2001 From: Justin Tieri <37750742+jtieri@users.noreply.github.com> Date: Wed, 21 Aug 2024 13:51:48 -0500 Subject: [PATCH 02/14] ci: configure additional ci jobs --- .codespellrc | 4 ++ .github/dependabot.yml | 14 ++++++ .github/mergify.yml | 15 ++++++ .github/workflows/codeql-analysis.yml | 61 +++++++++++++++++++++++ .github/workflows/markdown-link-check.yml | 11 ++++ .github/workflows/spell-check.yml | 24 +++++++++ .github/workflows/title-format.yml | 20 ++++++++ 7 files changed, 149 insertions(+) create mode 100644 .codespellrc create mode 100644 .github/dependabot.yml create mode 100644 .github/mergify.yml create mode 100644 .github/workflows/codeql-analysis.yml create mode 100644 .github/workflows/markdown-link-check.yml create mode 100644 .github/workflows/spell-check.yml create mode 100644 .github/workflows/title-format.yml diff --git a/.codespellrc b/.codespellrc new file mode 100644 index 00000000..d93e810d --- /dev/null +++ b/.codespellrc @@ -0,0 +1,4 @@ +[codespell] +skip = *.pulsar.go,*.pb.go,*.pb.gw.go,*.bin,*.sum,*.mod,*.git,*.json +ignore-words-list = usera,pres,crate +quiet-level = 3 \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..75b84468 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,14 @@ +version: 2 +updates: + # check dependencies in go.mod + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + # checks dependencies in github workflows + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 \ No newline at end of file diff --git a/.github/mergify.yml b/.github/mergify.yml new file mode 100644 index 00000000..47dfbbce --- /dev/null +++ b/.github/mergify.yml @@ -0,0 +1,15 @@ +# This mergify configuration is used for backporting only. This setup +# will backport a PR after being approved if it has the label 'backport'. +# Please see the comments below for configuring branches, labels, etc. +# +pull_request_rules: + - name: backport to maintained branches + conditions: + - label=backport # create a label in your project called backport + actions: + backport: + branches: # the list of branches the pull request should be copied to. + - main + assignees: # assign newly created backport PR to author + - "{{ author }}" + title: "`[BP: {{ destination_branch }} <- #{{ number }}]` {{ title }}" \ No newline at end of file diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 00000000..bd9acccf --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,61 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +name: "CodeQL" + +on: + push: + branches: [ main ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ main ] + schedule: + - cron: '59 23 * * 5' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'go' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] + # Learn more: + # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages. + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v3 + + # ✏️ If the Autobuild fails above, remove it and uncomment the following lines + # and modify them (or add more) to build your code. + + #- run: | + # make install + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 \ No newline at end of file diff --git a/.github/workflows/markdown-link-check.yml b/.github/workflows/markdown-link-check.yml new file mode 100644 index 00000000..3daf692b --- /dev/null +++ b/.github/workflows/markdown-link-check.yml @@ -0,0 +1,11 @@ +name: Markdown Link Check + +on: + pull_request: + +jobs: + link-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: gaurav-nelson/github-action-markdown-link-check@1.0.15 \ No newline at end of file diff --git a/.github/workflows/spell-check.yml b/.github/workflows/spell-check.yml new file mode 100644 index 00000000..96ef19cc --- /dev/null +++ b/.github/workflows/spell-check.yml @@ -0,0 +1,24 @@ +name: Spell Check + +on: + pull_request: + +jobs: + spellcheck: + name: Run codespell + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' + + - name: Install codespell + run: pip install codespell + + - name: Run codespell + run: codespell \ No newline at end of file diff --git a/.github/workflows/title-format.yml b/.github/workflows/title-format.yml new file mode 100644 index 00000000..b5e7d1a9 --- /dev/null +++ b/.github/workflows/title-format.yml @@ -0,0 +1,20 @@ +name: "Lint PR Title" + +on: + pull_request_target: + types: + - opened + - edited + - synchronize + +permissions: + pull-requests: read + +jobs: + main: + name: Validate PR title + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From 0d732aacfbd632c060010a837e21a8fd1a528c13 Mon Sep 17 00:00:00 2001 From: Justin Tieri <37750742+jtieri@users.noreply.github.com> Date: Wed, 21 Aug 2024 14:02:20 -0500 Subject: [PATCH 03/14] chore: fix broken links & fix grammar errors --- README.md | 8 ++++---- docs/CODE_OF_CONDUCT.md | 2 +- docs/metrics.md | 4 ++-- docs/migrating.md | 2 +- signer/metrics.go | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 5ac42d57..ca2eccec 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,11 @@ Take your validator infrastructure to the next level of security and availabilit Validator operators balance operational and risk tradeoffs to avoid penalties via slashing for liveliness faults or double signing blocks. -Traditional high-availability systems where the keys exist on hot spares risk double signing if there are failover detection bugs. Low-availability systems, or manual failover, risk downtime if manual intervention cannot respond in a timely manner. +Traditional high-availability systems where the keys exist on hot spares risk double signing if there are fail over detection bugs. Low-availability systems, or manual fail over, risk downtime if manual intervention cannot respond in a timely manner. -Multi-party computation using threshold signatures is able to provide high-availability while maintaining high security and avoiding double signing via consensus and failover detection mechanisms. +Multi-party computation using threshold signatures is able to provide high-availability while maintaining high security and avoiding double signing via consensus and fail over detection mechanisms. -For more on how the Horcrux MPC signing flow works, see [`docs/signing.md`](/docs/signing.md) +For more on how the Horcrux MPC signing flow works, see [`docs/signing.md`](./docs/signing.md) ![Screenshot from 2022-03-07 18-09-49](https://user-images.githubusercontent.com/6722152/157145772-8557b4b5-a0cc-4073-8834-86afda1900fc.png) @@ -39,7 +39,7 @@ Horcrux signer cluster configured with 5 total nodes, threshold 3. ## Running Horcrux -See documentation in [`docs/migrating.md`](/docs/migrating.md) to learn how to upgrade your validator infrastructure with Horcrux. +See documentation in [`docs/migrating.md`](./docs/migrating.md) to learn how to upgrade your validator infrastructure with Horcrux. ## Security diff --git a/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md index b5fc1364..6f138f46 100644 --- a/docs/CODE_OF_CONDUCT.md +++ b/docs/CODE_OF_CONDUCT.md @@ -2,7 +2,7 @@ ## Our Pledge -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socioeconomic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards diff --git a/docs/metrics.md b/docs/metrics.md index 24afd6f9..03526684 100644 --- a/docs/metrics.md +++ b/docs/metrics.md @@ -51,7 +51,7 @@ Single node signers don't execute any cosigner code, so the basic metrics are: If the 'seconds_since' metrics exceeds the normal block time, it may indicate a sentry failure or a network stall/halt. -If there are skips in the block heights requested to be signed the following counters will increase AFTER the sentry is able to report the latest block height. Until then, from the perspective of horcrux, it looks no different than a network stall. +If there are skips in the block heights requested to be signed the following counters will increase AFTER the sentry is able to report the latest block height. Until then, from the perspective of horcrux, it looks no different from a network stall. * signer_total_missed_precommits * signer_total_missed_prevotes @@ -87,7 +87,7 @@ As a result, followers also do not update these metrics ## Checking Signing Performance -We currently only have metrics between the leader and followers (not full p2p metrics). However it is still useful in determining when a particular peer lags significantly. +We currently only have metrics between the leader and followers (not full p2p metrics). However, it is still useful in determining when a particular peer lags significantly. Your cluster should reach the threshold for availability in a short time. Monitor the following: diff --git a/docs/migrating.md b/docs/migrating.md index b3046a41..9216e98a 100644 --- a/docs/migrating.md +++ b/docs/migrating.md @@ -206,7 +206,7 @@ The signer will continue retrying attempts to reach the sentries until we turn t - Misnaming or incorrect structure of the files in `~/.horcrux/state`. Double check these if you see errors - Misnaming or misplacement of the `~/.horcrux/{chain-id}_shard.json` file -> **NOTE:** leaving these logs streaming in seperate terminal windows will enable you to watch the cluster connect to the sentries. +> **NOTE:** leaving these logs streaming in separate terminal windows will enable you to watch the cluster connect to the sentries. ### 8. Configure and start your full nodes diff --git a/signer/metrics.go b/signer/metrics.go index 2145ba77..58b093da 100644 --- a/signer/metrics.go +++ b/signer/metrics.go @@ -252,7 +252,7 @@ var ( failedSignVote = promauto.NewCounterVec( prometheus.CounterOpts{ Name: "signer_total_failed_sign_vote", - Help: "Total Times Signer Failed to sign block - Unstarted and Unexepcted Height", + Help: "Total Times Signer Failed to sign block - Unstarted and Unexpected Height", }, []string{"chain_id"}, ) From 7c19d5bea2b655d50c4839ca7e408b93becc0d63 Mon Sep 17 00:00:00 2001 From: Justin Tieri <37750742+jtieri@users.noreply.github.com> Date: Wed, 21 Aug 2024 14:15:14 -0500 Subject: [PATCH 04/14] chore: fix linter errors and gofumpt project --- client/address_test.go | 3 ++- cmd/horcrux/cmd/address.go | 8 ++++--- cmd/horcrux/cmd/config.go | 3 ++- cmd/horcrux/cmd/config_test.go | 2 +- cmd/horcrux/cmd/leader_election.go | 6 ++--- cmd/horcrux/cmd/metrics.go | 6 ++--- cmd/horcrux/cmd/migrate.go | 12 ++++++---- cmd/horcrux/cmd/migrate_test.go | 33 +++++++++++++------------- cmd/horcrux/cmd/root.go | 3 ++- cmd/horcrux/cmd/shards.go | 9 +++---- cmd/horcrux/cmd/shards_test.go | 4 ++-- cmd/horcrux/cmd/start.go | 6 +++-- cmd/horcrux/cmd/state.go | 4 ++-- cmd/horcrux/cmd/state_test.go | 3 ++- cmd/horcrux/cmd/threshold.go | 3 ++- cmd/horcrux/cmd/version.go | 10 ++++---- signer/cond/cond_test.go | 3 ++- signer/config.go | 11 +++++---- signer/config_test.go | 7 +++--- signer/cosigner.go | 8 ++++--- signer/cosigner_grpc_server.go | 1 + signer/cosigner_health.go | 1 + signer/cosigner_health_test.go | 3 ++- signer/cosigner_key.go | 3 ++- signer/cosigner_key_shares.go | 15 ++++++------ signer/cosigner_nonce_cache.go | 3 ++- signer/cosigner_nonce_cache_test.go | 3 ++- signer/cosigner_security_ecies.go | 4 ++-- signer/cosigner_security_rsa.go | 4 ++-- signer/file.go | 13 +++++----- signer/io.go | 4 ++-- signer/local_cosigner.go | 23 +++++++++--------- signer/local_cosigner_test.go | 13 +++++----- signer/metrics.go | 4 ++-- signer/multiresolver/multi.go | 10 ++++---- signer/multiresolver/multi_test.go | 7 +++--- signer/raft_store.go | 14 ++++++----- signer/raft_store_test.go | 5 ++-- signer/remote_cosigner.go | 25 ++++++++++--------- signer/remote_signer.go | 2 +- signer/remote_signer_grpc_server.go | 5 ++-- signer/services.go | 2 +- signer/services_test.go | 11 +++++---- signer/sign_state.go | 6 +++-- signer/single_signer_validator.go | 6 ++--- signer/single_signer_validator_test.go | 19 +++++++-------- signer/threshold_signer.go | 2 +- signer/threshold_validator.go | 12 +++++----- signer/threshold_validator_test.go | 22 +++++++---------- test/horcrux_test.go | 2 -- test/validator_single.go | 3 ++- test/validator_threshold.go | 12 ++++------ 52 files changed, 218 insertions(+), 185 deletions(-) diff --git a/client/address_test.go b/client/address_test.go index 3296bba1..726ab27b 100644 --- a/client/address_test.go +++ b/client/address_test.go @@ -3,8 +3,9 @@ package client_test import ( "testing" - "github.com/strangelove-ventures/horcrux/v3/client" "github.com/stretchr/testify/require" + + "github.com/strangelove-ventures/horcrux/v3/client" ) func TestLeaderElectionMultiAddressDomain(t *testing.T) { diff --git a/cmd/horcrux/cmd/address.go b/cmd/horcrux/cmd/address.go index 644d577a..55b5f406 100644 --- a/cmd/horcrux/cmd/address.go +++ b/cmd/horcrux/cmd/address.go @@ -6,10 +6,13 @@ import ( "fmt" "strings" + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/types/bech32" + "github.com/cometbft/cometbft/crypto" cometprivval "github.com/cometbft/cometbft/privval" - "github.com/cosmos/cosmos-sdk/types/bech32" - "github.com/spf13/cobra" + "github.com/strangelove-ventures/horcrux/v3/signer" ) @@ -28,7 +31,6 @@ func addressCmd() *cobra.Command { SilenceUsage: true, Args: cobra.RangeArgs(1, 2), RunE: func(cmd *cobra.Command, args []string) error { - var pubKey crypto.PubKey chainID := args[0] diff --git a/cmd/horcrux/cmd/config.go b/cmd/horcrux/cmd/config.go index 6cdc6695..649d29fa 100644 --- a/cmd/horcrux/cmd/config.go +++ b/cmd/horcrux/cmd/config.go @@ -5,6 +5,7 @@ import ( "os" "github.com/spf13/cobra" + "github.com/strangelove-ventures/horcrux/v3/signer" ) @@ -123,7 +124,7 @@ for threshold signer mode, --cosigner flags and --threshold flag are required. cmd.SilenceUsage = true // create all directories up to the state directory - if err = os.MkdirAll(config.StateDir, 0755); err != nil { + if err = os.MkdirAll(config.StateDir, 0o755); err != nil { return err } // create the config file diff --git a/cmd/horcrux/cmd/config_test.go b/cmd/horcrux/cmd/config_test.go index dc5e492b..f1dc32ba 100644 --- a/cmd/horcrux/cmd/config_test.go +++ b/cmd/horcrux/cmd/config_test.go @@ -149,7 +149,7 @@ maxReadSize: 1048576 t.Run(tc.name, func(t *testing.T) { tmpConfig := filepath.Join(tc.home, ".horcrux") - err := os.MkdirAll(tc.home, 0777) + err := os.MkdirAll(tc.home, 0o777) require.NoError(t, err) cmd := rootCmd() diff --git a/cmd/horcrux/cmd/leader_election.go b/cmd/horcrux/cmd/leader_election.go index 9fb4dfd6..c2295990 100644 --- a/cmd/horcrux/cmd/leader_election.go +++ b/cmd/horcrux/cmd/leader_election.go @@ -7,12 +7,13 @@ import ( grpcretry "github.com/grpc-ecosystem/go-grpc-middleware/retry" "github.com/spf13/cobra" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "github.com/strangelove-ventures/horcrux/v3/client" "github.com/strangelove-ventures/horcrux/v3/signer" "github.com/strangelove-ventures/horcrux/v3/signer/multiresolver" "github.com/strangelove-ventures/horcrux/v3/signer/proto" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" ) func init() { @@ -178,5 +179,4 @@ func getLeaderCmd() *cobra.Command { return nil }, } - } diff --git a/cmd/horcrux/cmd/metrics.go b/cmd/horcrux/cmd/metrics.go index 078d3be5..1c8345eb 100644 --- a/cmd/horcrux/cmd/metrics.go +++ b/cmd/horcrux/cmd/metrics.go @@ -11,8 +11,9 @@ import ( "github.com/armon/go-metrics" gmprometheus "github.com/armon/go-metrics/prometheus" - cometlog "github.com/cometbft/cometbft/libs/log" "github.com/prometheus/client_golang/prometheus/promhttp" + + cometlog "github.com/cometbft/cometbft/libs/log" ) func AddPrometheusMetrics(mux *http.ServeMux, out io.Writer) { @@ -35,7 +36,7 @@ func AddPrometheusMetrics(mux *http.ServeMux, out io.Writer) { logger.Info("Prometheus Metrics Listening", "address", config.Config.DebugAddr, "path", "/metrics") } -// EnableDebugAndMetrics - Initialization errors are not fatal, only logged +// EnableDebugAndMetrics - Initialization errors are not fatal, only logged. func EnableDebugAndMetrics(ctx context.Context, out io.Writer) { logger := cometlog.NewTMLogger(cometlog.NewSyncWriter(out)).With("module", "debugserver") @@ -95,5 +96,4 @@ func EnableDebugAndMetrics(ctx context.Context, out io.Writer) { } } }() - } diff --git a/cmd/horcrux/cmd/migrate.go b/cmd/horcrux/cmd/migrate.go index d2a63963..b39ffef9 100644 --- a/cmd/horcrux/cmd/migrate.go +++ b/cmd/horcrux/cmd/migrate.go @@ -8,14 +8,16 @@ import ( "os" "path/filepath" + "github.com/spf13/cobra" + amino "github.com/tendermint/go-amino" + "gopkg.in/yaml.v2" + cometcrypto "github.com/cometbft/cometbft/crypto" cometcryptoed25519 "github.com/cometbft/cometbft/crypto/ed25519" cometcryptoencoding "github.com/cometbft/cometbft/crypto/encoding" cometprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" - "github.com/spf13/cobra" + "github.com/strangelove-ventures/horcrux/v3/signer" - amino "github.com/tendermint/go-amino" - "gopkg.in/yaml.v2" ) func legacyConfig() (*v2Config, error) { @@ -230,7 +232,7 @@ func migrateCmd() *cobra.Command { } newEd25519Path := config.KeyFilePathCosigner(chainID) - if err := os.WriteFile(newEd25519Path, newEd25519KeyBz, 0600); err != nil { + if err := os.WriteFile(newEd25519Path, newEd25519KeyBz, 0o600); err != nil { return fmt.Errorf("failed to write new Ed25519 key to %s: %w", newEd25519Path, err) } @@ -246,7 +248,7 @@ func migrateCmd() *cobra.Command { } newRSAPath := config.KeyFilePathCosignerRSA() - if err := os.WriteFile(newRSAPath, newRSAKeyBz, 0600); err != nil { + if err := os.WriteFile(newRSAPath, newRSAKeyBz, 0o600); err != nil { return fmt.Errorf("failed to write new RSA key to %s: %w", newRSAPath, err) } diff --git a/cmd/horcrux/cmd/migrate_test.go b/cmd/horcrux/cmd/migrate_test.go index b356723d..360ce93f 100644 --- a/cmd/horcrux/cmd/migrate_test.go +++ b/cmd/horcrux/cmd/migrate_test.go @@ -7,8 +7,9 @@ import ( "path/filepath" "testing" - "github.com/strangelove-ventures/horcrux/v3/cmd/horcrux/cmd/testdata" "github.com/stretchr/testify/require" + + "github.com/strangelove-ventures/horcrux/v3/cmd/horcrux/cmd/testdata" ) func TestMigrateV2toV3(t *testing.T) { @@ -16,12 +17,12 @@ func TestMigrateV2toV3(t *testing.T) { configFile := filepath.Join(tmp, "config.yaml") - err := os.WriteFile(configFile, testdata.ConfigV2, 0600) + err := os.WriteFile(configFile, testdata.ConfigV2, 0o600) require.NoError(t, err) keyShareFile := filepath.Join(tmp, "share.json") - err = os.WriteFile(keyShareFile, testdata.CosignerKeyV2, 0600) + err = os.WriteFile(keyShareFile, testdata.CosignerKeyV2, 0o600) require.NoError(t, err) cmd := rootCmd() @@ -57,7 +58,7 @@ func TestMigrateV2toV3(t *testing.T) { func appendToFile(file, append string) error { f, err := os.OpenFile(file, - os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644) if err != nil { return err } @@ -70,12 +71,12 @@ func TestMigrateV2toV3DifferentKeyFilePath(t *testing.T) { tmp := t.TempDir() keyDir := filepath.Join(tmp, "keys") - err := os.Mkdir(keyDir, 0700) + err := os.Mkdir(keyDir, 0o700) require.NoError(t, err) configFile := filepath.Join(tmp, "config.yaml") - err = os.WriteFile(configFile, testdata.ConfigV2, 0600) + err = os.WriteFile(configFile, testdata.ConfigV2, 0o600) require.NoError(t, err) keyShareFile := filepath.Join(keyDir, "share.json") @@ -83,7 +84,7 @@ func TestMigrateV2toV3DifferentKeyFilePath(t *testing.T) { err = appendToFile(configFile, fmt.Sprintf("key-file: %s", keyShareFile)) require.NoError(t, err) - err = os.WriteFile(keyShareFile, testdata.CosignerKeyV2, 0600) + err = os.WriteFile(keyShareFile, testdata.CosignerKeyV2, 0o600) require.NoError(t, err) cmd := rootCmd() @@ -117,13 +118,13 @@ func TestMigrateV2toV3DifferentKeyFilePath(t *testing.T) { require.Equal(t, fmt.Sprintf("keyDir: %s\n", keyDir)+testdata.ConfigMigrated, string(newConfigFileBz)) } -// Should migrate keys only if config has already been migrated +// Should migrate keys only if config has already been migrated. func TestMigrateV2toV3KeysOnly(t *testing.T) { tmp := t.TempDir() keyShareFile := filepath.Join(tmp, "share.json") - err := os.WriteFile(keyShareFile, testdata.CosignerKeyV2, 0600) + err := os.WriteFile(keyShareFile, testdata.CosignerKeyV2, 0o600) require.NoError(t, err) cmd := rootCmd() @@ -152,18 +153,18 @@ func TestMigrateV2toV3KeysOnly(t *testing.T) { require.Equal(t, testdata.CosignerRSAKeyMigrated, string(newRSAKeyFileBz)) } -// Should not modify config that is already in v3 format +// Should not modify config that is already in v3 format. func TestMigrateV2toV3ConfigAlreadyMigrated(t *testing.T) { tmp := t.TempDir() configFile := filepath.Join(tmp, "config.yaml") - err := os.WriteFile(configFile, []byte(testdata.ConfigMigrated), 0600) + err := os.WriteFile(configFile, []byte(testdata.ConfigMigrated), 0o600) require.NoError(t, err) keyShareFile := filepath.Join(tmp, "share.json") - err = os.WriteFile(keyShareFile, testdata.CosignerKeyV2, 0600) + err = os.WriteFile(keyShareFile, testdata.CosignerKeyV2, 0o600) require.NoError(t, err) cmd := rootCmd() @@ -197,23 +198,23 @@ func TestMigrateV2toV3ConfigAlreadyMigrated(t *testing.T) { require.Equal(t, testdata.ConfigMigrated, string(newConfigFileBz)) } -// Should not modify config or keys that are already in v3 format +// Should not modify config or keys that are already in v3 format. func TestMigrateV2toV3AlreadyMigrated(t *testing.T) { tmp := t.TempDir() configFile := filepath.Join(tmp, "config.yaml") - err := os.WriteFile(configFile, []byte(testdata.ConfigMigrated), 0600) + err := os.WriteFile(configFile, []byte(testdata.ConfigMigrated), 0o600) require.NoError(t, err) ed25519KeyShardFile := filepath.Join(tmp, "test_shard.json") - err = os.WriteFile(ed25519KeyShardFile, []byte(testdata.CosignerEd25519KeyMigrated), 0600) + err = os.WriteFile(ed25519KeyShardFile, []byte(testdata.CosignerEd25519KeyMigrated), 0o600) require.NoError(t, err) rsaKeyShardFile := filepath.Join(tmp, "rsa_keys.json") - err = os.WriteFile(rsaKeyShardFile, []byte(testdata.CosignerRSAKeyMigrated), 0600) + err = os.WriteFile(rsaKeyShardFile, []byte(testdata.CosignerRSAKeyMigrated), 0o600) require.NoError(t, err) cmd := rootCmd() diff --git a/cmd/horcrux/cmd/root.go b/cmd/horcrux/cmd/root.go index dd8e4ebc..ac61b984 100644 --- a/cmd/horcrux/cmd/root.go +++ b/cmd/horcrux/cmd/root.go @@ -8,8 +8,9 @@ import ( homedir "github.com/mitchellh/go-homedir" "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/strangelove-ventures/horcrux/v3/signer" "gopkg.in/yaml.v2" + + "github.com/strangelove-ventures/horcrux/v3/signer" ) var config signer.RuntimeConfig diff --git a/cmd/horcrux/cmd/shards.go b/cmd/horcrux/cmd/shards.go index 5af886d8..f34c5792 100644 --- a/cmd/horcrux/cmd/shards.go +++ b/cmd/horcrux/cmd/shards.go @@ -21,6 +21,7 @@ import ( "path/filepath" "github.com/spf13/cobra" + "github.com/strangelove-ventures/horcrux/v3/signer" ) @@ -31,7 +32,7 @@ func createCosignerDirectoryIfNecessary(out string, id int) (string, error) { if !os.IsNotExist(err) { return "", fmt.Errorf("unexpected error fetching info for cosigner directory: %w", err) } - if err := os.Mkdir(dir, 0700); err != nil { + if err := os.Mkdir(dir, 0o700); err != nil { return "", fmt.Errorf("failed to make directory for cosigner files: %w", err) } return dir, nil @@ -119,7 +120,7 @@ func createCosignerEd25519ShardsCmd() *cobra.Command { out, _ := cmd.Flags().GetString(flagOutputDir) if out != "" { - if err := os.MkdirAll(out, 0700); err != nil { + if err := os.MkdirAll(out, 0o700); err != nil { return err } } @@ -177,7 +178,7 @@ func createCosignerECIESShardsCmd() *cobra.Command { out, _ := cmd.Flags().GetString(flagOutputDir) if out != "" { - if err := os.MkdirAll(out, 0700); err != nil { + if err := os.MkdirAll(out, 0o700); err != nil { return err } } @@ -225,7 +226,7 @@ func createCosignerRSAShardsCmd() *cobra.Command { out, _ := cmd.Flags().GetString(flagOutputDir) if out != "" { - if err := os.MkdirAll(out, 0700); err != nil { + if err := os.MkdirAll(out, 0o700); err != nil { return err } } diff --git a/cmd/horcrux/cmd/shards_test.go b/cmd/horcrux/cmd/shards_test.go index a640376c..3d3b6f8a 100644 --- a/cmd/horcrux/cmd/shards_test.go +++ b/cmd/horcrux/cmd/shards_test.go @@ -5,9 +5,10 @@ import ( "path/filepath" "testing" + "github.com/stretchr/testify/require" + "github.com/cometbft/cometbft/crypto/ed25519" "github.com/cometbft/cometbft/privval" - "github.com/stretchr/testify/require" ) const testChainID = "test" @@ -89,7 +90,6 @@ func TestEd25519Shards(t *testing.T) { for _, tc := range tcs { t.Run(tc.name, func(t *testing.T) { - cmd := rootCmd() cmd.SetOutput(io.Discard) args := append([]string{"create-ed25519-shards", "--home", tmp, "--out", tmp}, tc.args...) diff --git a/cmd/horcrux/cmd/start.go b/cmd/horcrux/cmd/start.go index 66a26a67..ab81ddc4 100644 --- a/cmd/horcrux/cmd/start.go +++ b/cmd/horcrux/cmd/start.go @@ -4,9 +4,11 @@ import ( "fmt" "os" + "github.com/spf13/cobra" + cometlog "github.com/cometbft/cometbft/libs/log" "github.com/cometbft/cometbft/libs/service" - "github.com/spf13/cobra" + "github.com/strangelove-ventures/horcrux/v3/signer" ) @@ -30,7 +32,7 @@ func startCmd() *cobra.Command { } // create all directories up to the state directory - if err = os.MkdirAll(config.StateDir, 0700); err != nil { + if err = os.MkdirAll(config.StateDir, 0o700); err != nil { return err } diff --git a/cmd/horcrux/cmd/state.go b/cmd/horcrux/cmd/state.go index 63ee6a5e..50fef2f1 100644 --- a/cmd/horcrux/cmd/state.go +++ b/cmd/horcrux/cmd/state.go @@ -11,10 +11,11 @@ import ( "time" "github.com/spf13/cobra" - "github.com/strangelove-ventures/horcrux/v3/signer" cometjson "github.com/cometbft/cometbft/libs/json" cometlog "github.com/cometbft/cometbft/libs/log" + + "github.com/strangelove-ventures/horcrux/v3/signer" ) // Snippet Taken from https://raw.githubusercontent.com/cometbft/cometbft/main/privval/file.go @@ -46,7 +47,6 @@ func showStateCmd() *cobra.Command { Args: cobra.ExactArgs(1), SilenceUsage: true, RunE: func(cmd *cobra.Command, args []string) error { - chainID := args[0] if _, err := os.Stat(config.HomeDir); os.IsNotExist(err) { diff --git a/cmd/horcrux/cmd/state_test.go b/cmd/horcrux/cmd/state_test.go index e805e202..908c61d7 100644 --- a/cmd/horcrux/cmd/state_test.go +++ b/cmd/horcrux/cmd/state_test.go @@ -7,8 +7,9 @@ import ( "testing" "time" - "github.com/strangelove-ventures/horcrux/v3/signer" "github.com/stretchr/testify/require" + + "github.com/strangelove-ventures/horcrux/v3/signer" ) func TestStateSetCmd(t *testing.T) { diff --git a/cmd/horcrux/cmd/threshold.go b/cmd/horcrux/cmd/threshold.go index e0a57863..7e43901e 100644 --- a/cmd/horcrux/cmd/threshold.go +++ b/cmd/horcrux/cmd/threshold.go @@ -9,6 +9,7 @@ import ( cometlog "github.com/cometbft/cometbft/libs/log" cometservice "github.com/cometbft/cometbft/libs/service" + "github.com/strangelove-ventures/horcrux/v3/signer" ) @@ -70,7 +71,7 @@ func NewThresholdValidator( raftTimeout, _ := time.ParseDuration(thresholdCfg.RaftTimeout) raftDir := filepath.Join(config.HomeDir, "raft") - if err := os.MkdirAll(raftDir, 0700); err != nil { + if err := os.MkdirAll(raftDir, 0o700); err != nil { return nil, nil, fmt.Errorf("error creating raft directory: %w", err) } diff --git a/cmd/horcrux/cmd/version.go b/cmd/horcrux/cmd/version.go index ecead366..3e09fa1e 100644 --- a/cmd/horcrux/cmd/version.go +++ b/cmd/horcrux/cmd/version.go @@ -25,13 +25,13 @@ import ( ) var ( - // application's version string + // application's version string. Version = "" - // commit + // commit. Commit = "" - // sdk version + // sdk version. SDKVersion = "" - // tendermint version + // tendermint version. CBFTVersion = "" ) @@ -62,7 +62,7 @@ func NewInfo() Info { } } -// versionCmd represents the version command +// versionCmd represents the version command. func versionCmd() *cobra.Command { return &cobra.Command{ Use: "version", diff --git a/signer/cond/cond_test.go b/signer/cond/cond_test.go index fd64ede4..db7dc90f 100644 --- a/signer/cond/cond_test.go +++ b/signer/cond/cond_test.go @@ -5,8 +5,9 @@ import ( "sync" "testing" - "github.com/strangelove-ventures/horcrux/v3/signer/cond" "github.com/stretchr/testify/require" + + "github.com/strangelove-ventures/horcrux/v3/signer/cond" ) func TestRace(t *testing.T) { diff --git a/signer/config.go b/signer/config.go index 9ba07403..0acb6186 100644 --- a/signer/config.go +++ b/signer/config.go @@ -8,7 +8,8 @@ import ( "path/filepath" "time" - "github.com/cometbft/cometbft/crypto" + "gopkg.in/yaml.v2" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/legacy" "github.com/cosmos/cosmos-sdk/codec/types" @@ -16,8 +17,10 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/types/bech32" + + "github.com/cometbft/cometbft/crypto" + "github.com/strangelove-ventures/horcrux/v3/client" - "gopkg.in/yaml.v2" ) type SignMode string @@ -27,7 +30,7 @@ const ( SignModeSingle SignMode = "single" ) -// Config maps to the on-disk yaml format +// Config maps to the on-disk yaml format. type Config struct { PrivValKeyDir *string `yaml:"keyDir,omitempty"` SignMode SignMode `yaml:"signMode"` @@ -178,7 +181,7 @@ func (c RuntimeConfig) CosignerStateFile(chainID string) string { } func (c RuntimeConfig) WriteConfigFile() error { - return os.WriteFile(c.ConfigFile, c.Config.MustMarshalYaml(), 0600) + return os.WriteFile(c.ConfigFile, c.Config.MustMarshalYaml(), 0o600) } func fileExists(file string) error { diff --git a/signer/config_test.go b/signer/config_test.go index 19d48fdd..160e7a71 100644 --- a/signer/config_test.go +++ b/signer/config_test.go @@ -8,8 +8,9 @@ import ( "path/filepath" "testing" - "github.com/strangelove-ventures/horcrux/v3/signer" "github.com/stretchr/testify/require" + + "github.com/strangelove-ventures/horcrux/v3/signer" ) const testChainID = "test" @@ -429,7 +430,7 @@ func TestRuntimeConfigKeyFileExists(t *testing.T) { }, ).Error(), err.Error()) - err = os.WriteFile(keyFile, []byte{}, 0600) + err = os.WriteFile(keyFile, []byte{}, 0o600) require.NoError(t, err) _, err = c.KeyFileExistsCosigner(testChainID) @@ -449,7 +450,7 @@ func TestRuntimeConfigKeyFileExists(t *testing.T) { }, ).Error(), err.Error()) - err = os.WriteFile(keyFile, []byte{}, 0600) + err = os.WriteFile(keyFile, []byte{}, 0o600) require.NoError(t, err) _, err = c.KeyFileExistsSingleSigner(testChainID) diff --git a/signer/cosigner.go b/signer/cosigner.go index 216e7e59..d686fc8a 100644 --- a/signer/cosigner.go +++ b/signer/cosigner.go @@ -6,15 +6,17 @@ import ( "fmt" "time" + "github.com/google/uuid" + cometcrypto "github.com/cometbft/cometbft/crypto" "github.com/cometbft/cometbft/libs/protoio" cometproto "github.com/cometbft/cometbft/proto/tendermint/types" - "github.com/google/uuid" + "github.com/strangelove-ventures/horcrux/v3/signer/proto" ) // Cosigner interface is a set of methods for an m-of-n threshold signature. -// This interface abstracts the underlying key storage and management +// This interface abstracts the underlying key storage and management. type Cosigner interface { // Get the ID of the cosigner // The ID is the shamir index: 1, 2, etc... @@ -47,7 +49,7 @@ func (cosigners Cosigners) GetByID(id int) Cosigner { } // CosignerSignRequest is sent to a co-signer to obtain their signature for the SignBytes -// The SignBytes should be a serialized block +// The SignBytes should be a serialized block. type CosignerSignRequest struct { ChainID string SignBytes []byte diff --git a/signer/cosigner_grpc_server.go b/signer/cosigner_grpc_server.go index 1522ae15..12c03dc0 100644 --- a/signer/cosigner_grpc_server.go +++ b/signer/cosigner_grpc_server.go @@ -6,6 +6,7 @@ import ( "github.com/google/uuid" "github.com/hashicorp/raft" + "github.com/strangelove-ventures/horcrux/v3/signer/proto" ) diff --git a/signer/cosigner_health.go b/signer/cosigner_health.go index 94697ce1..50426f7a 100644 --- a/signer/cosigner_health.go +++ b/signer/cosigner_health.go @@ -7,6 +7,7 @@ import ( "time" cometlog "github.com/cometbft/cometbft/libs/log" + "github.com/strangelove-ventures/horcrux/v3/signer/proto" ) diff --git a/signer/cosigner_health_test.go b/signer/cosigner_health_test.go index 4f7398c2..b4c95344 100644 --- a/signer/cosigner_health_test.go +++ b/signer/cosigner_health_test.go @@ -4,8 +4,9 @@ import ( "os" "testing" - cometlog "github.com/cometbft/cometbft/libs/log" "github.com/stretchr/testify/require" + + cometlog "github.com/cometbft/cometbft/libs/log" ) func TestCosignerHealth(t *testing.T) { diff --git a/signer/cosigner_key.go b/signer/cosigner_key.go index 8aaa396d..aaa2ea13 100644 --- a/signer/cosigner_key.go +++ b/signer/cosigner_key.go @@ -4,11 +4,12 @@ import ( "encoding/json" "os" + amino "github.com/tendermint/go-amino" + cometcrypto "github.com/cometbft/cometbft/crypto" cometcryptoed25519 "github.com/cometbft/cometbft/crypto/ed25519" cometcryptoencoding "github.com/cometbft/cometbft/crypto/encoding" cometprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" - amino "github.com/tendermint/go-amino" ) // CosignerEd25519Key is a single Ed255219 key shard for an m-of-n threshold signer. diff --git a/signer/cosigner_key_shares.go b/signer/cosigner_key_shares.go index 0aee38a5..54dcb114 100644 --- a/signer/cosigner_key_shares.go +++ b/signer/cosigner_key_shares.go @@ -6,15 +6,16 @@ import ( "encoding/json" "os" - cometjson "github.com/cometbft/cometbft/libs/json" - "github.com/cometbft/cometbft/privval" "github.com/ethereum/go-ethereum/crypto/ecies" "github.com/ethereum/go-ethereum/crypto/secp256k1" tsed25519 "gitlab.com/unit410/threshold-ed25519/pkg" "golang.org/x/sync/errgroup" + + cometjson "github.com/cometbft/cometbft/libs/json" + "github.com/cometbft/cometbft/privval" ) -// CreateCosignerEd25519ShardsFromFile creates CosignerEd25519Key objects from a priv_validator_key.json file +// CreateCosignerEd25519ShardsFromFile creates CosignerEd25519Key objects from a priv_validator_key.json file. func CreateCosignerEd25519ShardsFromFile(priv string, threshold, shards uint8) ([]CosignerEd25519Key, error) { pv, err := ReadPrivValidatorFile(priv) if err != nil { @@ -23,7 +24,7 @@ func CreateCosignerEd25519ShardsFromFile(priv string, threshold, shards uint8) ( return CreateCosignerEd25519Shards(pv, threshold, shards), nil } -// CreateCosignerEd25519Shards creates CosignerEd25519Key objects from a privval.FilePVKey +// CreateCosignerEd25519Shards creates CosignerEd25519Key objects from a privval.FilePVKey. func CreateCosignerEd25519Shards(pv privval.FilePVKey, threshold, shards uint8) []CosignerEd25519Key { privShards := tsed25519.DealShares(tsed25519.ExpandSecret(pv.PrivKey.Bytes()[:32]), threshold, shards) out := make([]CosignerEd25519Key, shards) @@ -72,7 +73,7 @@ func WriteCosignerEd25519ShardFile(cosigner CosignerEd25519Key, file string) err if err != nil { return err } - return os.WriteFile(file, jsonBytes, 0600) + return os.WriteFile(file, jsonBytes, 0o600) } // WriteCosignerRSAShardFile writes a cosigner RSA key to a given file name. @@ -81,7 +82,7 @@ func WriteCosignerRSAShardFile(cosigner CosignerRSAKey, file string) error { if err != nil { return err } - return os.WriteFile(file, jsonBytes, 0600) + return os.WriteFile(file, jsonBytes, 0o600) } // CreateCosignerECIESShards generates CosignerECIESKey objects. @@ -107,7 +108,7 @@ func WriteCosignerECIESShardFile(cosigner CosignerECIESKey, file string) error { if err != nil { return err } - return os.WriteFile(file, jsonBytes, 0600) + return os.WriteFile(file, jsonBytes, 0o600) } func makeRSAKeys(num int) (rsaKeys []*rsa.PrivateKey, pubKeys []*rsa.PublicKey, err error) { diff --git a/signer/cosigner_nonce_cache.go b/signer/cosigner_nonce_cache.go index 327bd00b..598166ed 100644 --- a/signer/cosigner_nonce_cache.go +++ b/signer/cosigner_nonce_cache.go @@ -7,8 +7,9 @@ import ( "sync/atomic" "time" - cometlog "github.com/cometbft/cometbft/libs/log" "github.com/google/uuid" + + cometlog "github.com/cometbft/cometbft/libs/log" ) const ( diff --git a/signer/cosigner_nonce_cache_test.go b/signer/cosigner_nonce_cache_test.go index 2c65f175..91fb3c85 100644 --- a/signer/cosigner_nonce_cache_test.go +++ b/signer/cosigner_nonce_cache_test.go @@ -7,9 +7,10 @@ import ( "testing" "time" - cometlog "github.com/cometbft/cometbft/libs/log" "github.com/google/uuid" "github.com/stretchr/testify/require" + + cometlog "github.com/cometbft/cometbft/libs/log" ) func TestNonceCache(_ *testing.T) { diff --git a/signer/cosigner_security_ecies.go b/signer/cosigner_security_ecies.go index cde12d12..073a06b1 100644 --- a/signer/cosigner_security_ecies.go +++ b/signer/cosigner_security_ecies.go @@ -9,10 +9,11 @@ import ( "math/big" "os" - cometjson "github.com/cometbft/cometbft/libs/json" "github.com/ethereum/go-ethereum/crypto/ecies" "github.com/ethereum/go-ethereum/crypto/secp256k1" "golang.org/x/sync/errgroup" + + cometjson "github.com/cometbft/cometbft/libs/json" ) var _ CosignerSecurity = &CosignerSecurityECIES{} @@ -172,7 +173,6 @@ func (c *CosignerSecurityECIES) EncryptAndSign(id int, noncePub []byte, nonceSha // cosigners can verify the signature to confirm sender validity jsonBytes, err := cometjson.Marshal(nonce) - if err != nil { return nonce, err } diff --git a/signer/cosigner_security_rsa.go b/signer/cosigner_security_rsa.go index eb46b442..c6bd8a81 100644 --- a/signer/cosigner_security_rsa.go +++ b/signer/cosigner_security_rsa.go @@ -10,8 +10,9 @@ import ( "fmt" "os" - cometjson "github.com/cometbft/cometbft/libs/json" "golang.org/x/sync/errgroup" + + cometjson "github.com/cometbft/cometbft/libs/json" ) var _ CosignerSecurity = &CosignerSecurityRSA{} @@ -164,7 +165,6 @@ func (c *CosignerSecurityRSA) EncryptAndSign(id int, noncePub []byte, nonceShare // cosigners can verify the signature to confirm sender validity jsonBytes, err := cometjson.Marshal(nonce) - if err != nil { return nonce, err } diff --git a/signer/file.go b/signer/file.go index d4379dbc..59377412 100644 --- a/signer/file.go +++ b/signer/file.go @@ -41,7 +41,7 @@ func (pvKey FilePVKey) Save() { panic(err) } - if err := tempfile.WriteFileAtomic(outFile, jsonBytes, 0600); err != nil { + if err := tempfile.WriteFileAtomic(outFile, jsonBytes, 0o600); err != nil { panic(err) } } @@ -67,7 +67,6 @@ type FilePVLastSignState struct { // we have already signed for this HRS, and can reuse the existing signature). // It panics if the HRS matches the arguments, there's a SignBytes, but no Signature. func (lss *FilePVLastSignState) CheckHRS(height int64, round int32, step int8) (bool, error) { - if lss.Height > height { return false, fmt.Errorf("height regression. Got %v, last height %v", height, lss.Height) } @@ -110,7 +109,7 @@ func (lss *FilePVLastSignState) Save() { if err != nil { panic(err) } - err = tempfile.WriteFileAtomic(outFile, jsonBytes, 0600) + err = tempfile.WriteFileAtomic(outFile, jsonBytes, 0o600) if err != nil { panic(err) } @@ -290,10 +289,10 @@ func (pv *FilePV) String() string { ) } -// Persist height/round/step and signature +// Persist height/round/step and signature. func (pv *FilePV) saveSigned(height int64, round int32, step int8, - signBytes []byte, sig []byte) { - + signBytes []byte, sig []byte, +) { pv.LastSignState.Height = height pv.LastSignState.Round = round pv.LastSignState.Step = step @@ -325,7 +324,7 @@ func checkVotesOnlyDifferByTimestamp(lastSignBytes, newSignBytes []byte) (time.T } // returns the timestamp from the lastSignBytes. -// returns true if the only difference in the proposals is their timestamp +// returns true if the only difference in the proposals is their timestamp. func checkProposalsOnlyDifferByTimestamp(lastSignBytes, newSignBytes []byte) (time.Time, bool) { var lastProposal, newProposal cometproto.CanonicalProposal if err := protoio.UnmarshalDelimited(lastSignBytes, &lastProposal); err != nil { diff --git a/signer/io.go b/signer/io.go index 690ba2af..151d82a3 100644 --- a/signer/io.go +++ b/signer/io.go @@ -7,7 +7,7 @@ import ( cometprotoprivval "github.com/cometbft/cometbft/proto/tendermint/privval" ) -// ReadMsg reads a message from an io.Reader +// ReadMsg reads a message from an io.Reader. func ReadMsg(reader io.Reader, maxReadSize int) (msg cometprotoprivval.Message, err error) { if maxReadSize <= 0 { maxReadSize = 1024 * 1024 // 1MB @@ -17,7 +17,7 @@ func ReadMsg(reader io.Reader, maxReadSize int) (msg cometprotoprivval.Message, return msg, err } -// WriteMsg writes a message to an io.Writer +// WriteMsg writes a message to an io.Writer. func WriteMsg(writer io.Writer, msg cometprotoprivval.Message) (err error) { protoWriter := protoio.NewDelimitedWriter(writer) _, err = protoWriter.WriteMsg(&msg) diff --git a/signer/local_cosigner.go b/signer/local_cosigner.go index 4559974f..602efe6e 100644 --- a/signer/local_cosigner.go +++ b/signer/local_cosigner.go @@ -7,11 +7,12 @@ import ( "sync" "time" + "github.com/google/uuid" + "golang.org/x/sync/errgroup" + cometcrypto "github.com/cometbft/cometbft/crypto" cometcryptoed25519 "github.com/cometbft/cometbft/crypto/ed25519" cometlog "github.com/cometbft/cometbft/libs/log" - "github.com/google/uuid" - "golang.org/x/sync/errgroup" ) var _ Cosigner = &LocalCosigner{} @@ -133,13 +134,13 @@ func (cosigner *LocalCosigner) waitForSignStatesToFlushToDisk() { } // GetID returns the id of the cosigner -// Implements Cosigner interface +// Implements Cosigner interface. func (cosigner *LocalCosigner) GetID() int { return cosigner.security.GetID() } // GetAddress returns the RPC URL of the cosigner -// Implements Cosigner interface +// Implements Cosigner interface. func (cosigner *LocalCosigner) GetAddress() string { return cosigner.address } @@ -159,7 +160,7 @@ func (cosigner *LocalCosigner) getChainState(chainID string) (*ChainState, error } // GetPubKey returns public key of the validator. -// Implements Cosigner interface +// Implements Cosigner interface. func (cosigner *LocalCosigner) GetPubKey(chainID string) (cometcrypto.PubKey, error) { if err := cosigner.LoadSignStateIfNecessary(chainID); err != nil { return nil, err @@ -184,7 +185,7 @@ func (cosigner *LocalCosigner) CombineSignatures(chainID string, signatures []Pa } // VerifySignature validates a signed payload against the public key. -// Implements Cosigner interface +// Implements Cosigner interface. func (cosigner *LocalCosigner) VerifySignature(chainID string, payload, signature []byte) bool { if err := cosigner.LoadSignStateIfNecessary(chainID); err != nil { return false @@ -203,7 +204,7 @@ func (cosigner *LocalCosigner) VerifySignature(chainID string, payload, signatur // Sign the sign request using the cosigner's shard // Return the signed bytes or an error -// Implements Cosigner interface +// Implements Cosigner interface. func (cosigner *LocalCosigner) sign(req CosignerSignRequest) (CosignerSignResponse, error) { chainID := req.ChainID @@ -288,7 +289,6 @@ func (cosigner *LocalCosigner) sign(req CosignerSignRequest) (CosignerSignRespon SignBytes: req.SignBytes, VoteExtensionSignature: res.VoteExtensionSignature, }, &cosigner.pendingDiskWG) - if err != nil { if _, isSameHRSError := err.(*SameHRSError); !isSameHRSError { return res, err @@ -449,7 +449,7 @@ func (cosigner *LocalCosigner) generateNoncesIfNecessary(uuid uuid.UUID) (*Nonce } // Get the ephemeral secret part for an ephemeral share -// The ephemeral secret part is encrypted for the receiver +// The ephemeral secret part is encrypted for the receiver. func (cosigner *LocalCosigner) getNonce( meta *NoncesWithExpiration, peerID int, @@ -469,7 +469,7 @@ func (cosigner *LocalCosigner) getNonce( const errUnexpectedState = "unexpected state, metadata does not exist for U:" -// setNonce stores a nonce provided by another cosigner +// setNonce stores a nonce provided by another cosigner. func (cosigner *LocalCosigner) setNonce(uuid uuid.UUID, nonce CosignerNonce) error { // Verify the source signature if nonce.Signature == nil { @@ -508,7 +508,8 @@ func (cosigner *LocalCosigner) setNonce(uuid uuid.UUID, nonce CosignerNonce) err func (cosigner *LocalCosigner) SetNoncesAndSign( _ context.Context, - req CosignerSetNoncesAndSignRequest) (*CosignerSignResponse, error) { + req CosignerSetNoncesAndSignRequest, +) (*CosignerSignResponse, error) { chainID := req.ChainID if err := cosigner.LoadSignStateIfNecessary(chainID); err != nil { diff --git a/signer/local_cosigner_test.go b/signer/local_cosigner_test.go index 462da002..adeacd7e 100644 --- a/signer/local_cosigner_test.go +++ b/signer/local_cosigner_test.go @@ -10,15 +10,16 @@ import ( "testing" "time" - cometcryptoed25519 "github.com/cometbft/cometbft/crypto/ed25519" - "github.com/cometbft/cometbft/libs/log" - cometproto "github.com/cometbft/cometbft/proto/tendermint/types" - comet "github.com/cometbft/cometbft/types" "github.com/ethereum/go-ethereum/crypto/ecies" "github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/google/uuid" "github.com/stretchr/testify/require" tsed25519 "gitlab.com/unit410/threshold-ed25519/pkg" + + cometcryptoed25519 "github.com/cometbft/cometbft/crypto/ed25519" + "github.com/cometbft/cometbft/libs/log" + cometproto "github.com/cometbft/cometbft/proto/tendermint/types" + comet "github.com/cometbft/cometbft/types" ) const ( @@ -147,7 +148,7 @@ func testLocalCosignerSign(t *testing.T, threshold, total uint8, security []Cosi } cosignerDir := filepath.Join(tmpDir, fmt.Sprintf("cosigner%d", id)) - err := os.Mkdir(cosignerDir, 0700) + err := os.Mkdir(cosignerDir, 0o700) require.NoError(t, err) cosigner := NewLocalCosigner( @@ -163,7 +164,7 @@ func testLocalCosignerSign(t *testing.T, threshold, total uint8, security []Cosi keyBz, err := key.MarshalJSON() require.NoError(t, err) - err = os.WriteFile(cosigner.config.KeyFilePathCosigner(testChainID), keyBz, 0600) + err = os.WriteFile(cosigner.config.KeyFilePathCosigner(testChainID), keyBz, 0o600) require.NoError(t, err) defer cosigner.waitForSignStatesToFlushToDisk() diff --git a/signer/metrics.go b/signer/metrics.go index 58b093da..851eadcd 100644 --- a/signer/metrics.go +++ b/signer/metrics.go @@ -68,12 +68,12 @@ func (mt *metricsTimer) UpdatePrometheusMetrics() { } var ( - // Variables to calculate Prometheus Metrics + // Variables to calculate Prometheus Metrics. previousPrecommitHeight = int64(0) previousPrevoteHeight = int64(0) metricsTimeKeeper = newMetricsTimer() - // Prometheus Metrics + // Prometheus Metrics. totalPubKeyRequests = promauto.NewCounterVec( prometheus.CounterOpts{ Name: "signer_total_pubkey_requests", diff --git a/signer/multiresolver/multi.go b/signer/multiresolver/multi.go index 82e5bc6e..7fbb7699 100644 --- a/signer/multiresolver/multi.go +++ b/signer/multiresolver/multi.go @@ -17,11 +17,13 @@ import ( "google.golang.org/grpc/serviceconfig" ) -var _ resolver.Builder = builder{} -var _ resolver.ClientConn = &partialClientConn{} -var _ resolver.Resolver = &multiResolver{} +var ( + _ resolver.Builder = builder{} + _ resolver.ClientConn = &partialClientConn{} + _ resolver.Resolver = &multiResolver{} +) -// Register registers the multiresolver builder +// Register registers the multiresolver builder. func Register() { resolver.Register(builder{}) } diff --git a/signer/multiresolver/multi_test.go b/signer/multiresolver/multi_test.go index 236c07df..9a716d85 100644 --- a/signer/multiresolver/multi_test.go +++ b/signer/multiresolver/multi_test.go @@ -10,12 +10,13 @@ import ( "time" grpcretry "github.com/grpc-ecosystem/go-grpc-middleware/retry" - "github.com/strangelove-ventures/horcrux/v3/signer" - "github.com/strangelove-ventures/horcrux/v3/signer/multiresolver" - "github.com/strangelove-ventures/horcrux/v3/signer/proto" "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" + + "github.com/strangelove-ventures/horcrux/v3/signer" + "github.com/strangelove-ventures/horcrux/v3/signer/multiresolver" + "github.com/strangelove-ventures/horcrux/v3/signer/proto" ) func createListener(nodeID string, homedir string) (string, func(), error) { diff --git a/signer/raft_store.go b/signer/raft_store.go index 4cff36b3..79340ac1 100644 --- a/signer/raft_store.go +++ b/signer/raft_store.go @@ -22,14 +22,16 @@ import ( "github.com/Jille/raft-grpc-leader-rpc/leaderhealth" raftgrpctransport "github.com/Jille/raft-grpc-transport" "github.com/Jille/raftadmin" - "github.com/cometbft/cometbft/libs/log" - "github.com/cometbft/cometbft/libs/service" "github.com/hashicorp/raft" boltdb "github.com/hashicorp/raft-boltdb/v2" - "github.com/strangelove-ventures/horcrux/v3/signer/proto" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/reflection" + + "github.com/cometbft/cometbft/libs/log" + "github.com/cometbft/cometbft/libs/service" + + "github.com/strangelove-ventures/horcrux/v3/signer/proto" ) var _ Leader = (*RaftStore)(nil) @@ -67,7 +69,8 @@ type RaftStore struct { // New returns a new Store. func NewRaftStore( nodeID string, directory string, bindAddress string, timeout time.Duration, - logger log.Logger, cosigner *LocalCosigner, cosigners []Cosigner) *RaftStore { + logger log.Logger, cosigner *LocalCosigner, cosigners []Cosigner, +) *RaftStore { cosignerRaftStore := &RaftStore{ NodeID: nodeID, RaftDir: directory, @@ -111,7 +114,7 @@ func (s *RaftStore) init() error { return grpcServer.Serve(sock) } -// OnStart starts the raft server +// OnStart starts the raft server. func (s *RaftStore) OnStart() error { go func() { err := s.init() @@ -399,7 +402,6 @@ func (f *fsmSnapshot) Persist(sink raft.SnapshotSink) error { // Close the sink. return sink.Close() }() - if err != nil { f.logger.Error("Snapshot persist error", err.Error()) sinkErr := sink.Cancel() diff --git a/signer/raft_store_test.go b/signer/raft_store_test.go index c7b051e8..4678b51e 100644 --- a/signer/raft_store_test.go +++ b/signer/raft_store_test.go @@ -6,11 +6,12 @@ import ( "testing" "time" - cometcryptoed25519 "github.com/cometbft/cometbft/crypto/ed25519" - "github.com/cometbft/cometbft/libs/log" "github.com/ethereum/go-ethereum/crypto/ecies" "github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/stretchr/testify/require" + + cometcryptoed25519 "github.com/cometbft/cometbft/crypto/ed25519" + "github.com/cometbft/cometbft/libs/log" ) // Test_StoreInMemOpenSingleNode tests that a command can be applied to the log diff --git a/signer/remote_cosigner.go b/signer/remote_cosigner.go index dfb12350..a98a68a3 100644 --- a/signer/remote_cosigner.go +++ b/signer/remote_cosigner.go @@ -6,16 +6,18 @@ import ( "net/url" "time" - cometcrypto "github.com/cometbft/cometbft/crypto" "github.com/google/uuid" - "github.com/strangelove-ventures/horcrux/v3/signer/proto" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" + + cometcrypto "github.com/cometbft/cometbft/crypto" + + "github.com/strangelove-ventures/horcrux/v3/signer/proto" ) var _ Cosigner = &RemoteCosigner{} -// RemoteCosigner uses CosignerGRPC to request signing from a remote cosigner +// RemoteCosigner uses CosignerGRPC to request signing from a remote cosigner. type RemoteCosigner struct { id int address string @@ -23,7 +25,7 @@ type RemoteCosigner struct { client proto.CosignerClient } -// NewRemoteCosigner returns a newly initialized RemoteCosigner +// NewRemoteCosigner returns a newly initialized RemoteCosigner. func NewRemoteCosigner(id int, address string) (*RemoteCosigner, error) { client, err := getGRPCClient(address) if err != nil { @@ -40,25 +42,25 @@ func NewRemoteCosigner(id int, address string) (*RemoteCosigner, error) { } // GetID returns the ID of the remote cosigner -// Implements the cosigner interface +// Implements the cosigner interface. func (cosigner *RemoteCosigner) GetID() int { return cosigner.id } // GetAddress returns the P2P URL of the remote cosigner -// Implements the cosigner interface +// Implements the cosigner interface. func (cosigner *RemoteCosigner) GetAddress() string { return cosigner.address } // GetPubKey returns public key of the validator. -// Implements Cosigner interface +// Implements Cosigner interface. func (cosigner *RemoteCosigner) GetPubKey(_ string) (cometcrypto.PubKey, error) { return nil, fmt.Errorf("unexpected call to RemoteCosigner.GetPubKey") } // VerifySignature validates a signed payload against the public key. -// Implements Cosigner interface +// Implements Cosigner interface. func (cosigner *RemoteCosigner) VerifySignature(_ string, _, _ []byte) bool { return false } @@ -78,7 +80,7 @@ func getGRPCClient(address string) (proto.CosignerClient, error) { return proto.NewCosignerClient(conn), nil } -// Implements the cosigner interface +// Implements the cosigner interface. func (cosigner *RemoteCosigner) GetNonces( ctx context.Context, uuids []uuid.UUID, @@ -104,10 +106,11 @@ func (cosigner *RemoteCosigner) GetNonces( return out, nil } -// Implements the cosigner interface +// Implements the cosigner interface. func (cosigner *RemoteCosigner) SetNoncesAndSign( ctx context.Context, - req CosignerSetNoncesAndSignRequest) (*CosignerSignResponse, error) { + req CosignerSetNoncesAndSignRequest, +) (*CosignerSignResponse, error) { cosignerReq := &proto.SetNoncesAndSignRequest{ Uuid: req.Nonces.UUID[:], ChainID: req.ChainID, diff --git a/signer/remote_signer.go b/signer/remote_signer.go index 53dfd9a8..c1d34a9a 100644 --- a/signer/remote_signer.go +++ b/signer/remote_signer.go @@ -95,7 +95,7 @@ func (rs *ReconnRemoteSigner) establishConnection(ctx context.Context) (net.Conn return conn, nil } -// main loop for ReconnRemoteSigner +// main loop for ReconnRemoteSigner. func (rs *ReconnRemoteSigner) loop(ctx context.Context) { var conn net.Conn for { diff --git a/signer/remote_signer_grpc_server.go b/signer/remote_signer_grpc_server.go index 797735ad..2e7219ab 100644 --- a/signer/remote_signer_grpc_server.go +++ b/signer/remote_signer_grpc_server.go @@ -6,12 +6,13 @@ import ( "net" "time" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" + cometlog "github.com/cometbft/cometbft/libs/log" cometservice "github.com/cometbft/cometbft/libs/service" "github.com/strangelove-ventures/horcrux/v3/signer/proto" - "google.golang.org/grpc" - "google.golang.org/grpc/reflection" ) var _ proto.RemoteSignerServer = &RemoteSignerGRPCServer{} diff --git a/signer/services.go b/signer/services.go index e6263f06..d649717d 100644 --- a/signer/services.go +++ b/signer/services.go @@ -77,7 +77,7 @@ func RequireNotRunning(log cometlog.Logger, pidFilePath string) error { func WaitAndTerminate(logger cometlog.Logger, services []cometservice.Service, pidFilePath string) { done := make(chan struct{}) - pidFile, err := os.OpenFile(pidFilePath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600) + pidFile, err := os.OpenFile(pidFilePath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o600) if err != nil { panic(fmt.Errorf("error opening PID file: %s. %w", pidFilePath, err)) } diff --git a/signer/services_test.go b/signer/services_test.go index 48f35dae..f4d92143 100644 --- a/signer/services_test.go +++ b/signer/services_test.go @@ -12,12 +12,13 @@ import ( "testing" "time" + fork "github.com/kraken-hpc/go-fork" + "github.com/stretchr/testify/require" + cometlog "github.com/cometbft/cometbft/libs/log" cometservice "github.com/cometbft/cometbft/libs/service" - "github.com/strangelove-ventures/horcrux/v3/signer" - fork "github.com/kraken-hpc/go-fork" - "github.com/stretchr/testify/require" + "github.com/strangelove-ventures/horcrux/v3/signer" ) func init() { @@ -29,7 +30,7 @@ func mockHorcruxChildProcess(pidFilePath string) { _ = os.WriteFile( pidFilePath, []byte(fmt.Sprintf("%d\n", os.Getpid())), - 0600, + 0o600, ) } @@ -125,7 +126,7 @@ func TestIsRunningNonExistentPid(t *testing.T) { err = os.WriteFile( pidFilePath, []byte(fmt.Sprintf("%d\n", pid)), - 0600, + 0o600, ) require.NoError(t, err, "error writing pid file") diff --git a/signer/sign_state.go b/signer/sign_state.go index f6c55eb0..3e712a00 100644 --- a/signer/sign_state.go +++ b/signer/sign_state.go @@ -8,13 +8,15 @@ import ( "os" "sync" + "github.com/gogo/protobuf/proto" + cometbytes "github.com/cometbft/cometbft/libs/bytes" cometjson "github.com/cometbft/cometbft/libs/json" "github.com/cometbft/cometbft/libs/protoio" "github.com/cometbft/cometbft/libs/tempfile" cometproto "github.com/cometbft/cometbft/proto/tendermint/types" comet "github.com/cometbft/cometbft/types" - "github.com/gogo/protobuf/proto" + "github.com/strangelove-ventures/horcrux/v3/signer/cond" ) @@ -287,7 +289,7 @@ func (signState *SignState) save(jsonBytes []byte) { panic("cannot save SignState: filePath not set") } - err := tempfile.WriteFileAtomic(outFile, jsonBytes, 0600) + err := tempfile.WriteFileAtomic(outFile, jsonBytes, 0o600) if err != nil { panic(err) } diff --git a/signer/single_signer_validator.go b/signer/single_signer_validator.go index 846e283d..1445b045 100644 --- a/signer/single_signer_validator.go +++ b/signer/single_signer_validator.go @@ -11,7 +11,7 @@ import ( var _ PrivValidator = &SingleSignerValidator{} // SingleSignerValidator guards access to an underlying PrivValidator by using mutexes -// for each of the PrivValidator interface functions +// for each of the PrivValidator interface functions. type SingleSignerValidator struct { config *RuntimeConfig chainState sync.Map @@ -35,7 +35,7 @@ func NewSingleSignerValidator(config *RuntimeConfig) *SingleSignerValidator { } } -// GetPubKey implements types.PrivValidator +// GetPubKey implements types.PrivValidator. func (pv *SingleSignerValidator) GetPubKey(_ context.Context, chainID string) ([]byte, error) { chainState, err := pv.loadChainStateIfNecessary(chainID) if err != nil { @@ -48,7 +48,7 @@ func (pv *SingleSignerValidator) GetPubKey(_ context.Context, chainID string) ([ return pubKey.Bytes(), nil } -// SignVote implements types.PrivValidator +// SignVote implements types.PrivValidator. func (pv *SingleSignerValidator) Sign( _ context.Context, chainID string, diff --git a/signer/single_signer_validator_test.go b/signer/single_signer_validator_test.go index 721ec234..7139a50c 100644 --- a/signer/single_signer_validator_test.go +++ b/signer/single_signer_validator_test.go @@ -2,11 +2,10 @@ package signer import ( "context" - "path/filepath" - "time" - "os" + "path/filepath" "testing" + "time" cometcryptoed25519 "github.com/cometbft/cometbft/crypto/ed25519" "github.com/cometbft/cometbft/crypto/tmhash" @@ -14,7 +13,6 @@ import ( cometrand "github.com/cometbft/cometbft/libs/rand" cometprivval "github.com/cometbft/cometbft/privval" cometproto "github.com/cometbft/cometbft/proto/tendermint/types" - "github.com/stretchr/testify/require" ) func TestSingleSignerValidator(t *testing.T) { @@ -23,7 +21,7 @@ func TestSingleSignerValidator(t *testing.T) { tmpDir := t.TempDir() stateDir := filepath.Join(tmpDir, "state") - err := os.MkdirAll(stateDir, 0700) + err := os.MkdirAll(stateDir, 0o700) require.NoError(t, err) runtimeConfig := &RuntimeConfig{ @@ -40,10 +38,10 @@ func TestSingleSignerValidator(t *testing.T) { }) require.NoError(t, err) - err = os.WriteFile(runtimeConfig.KeyFilePathSingleSigner(testChainID), marshaled, 0600) + err = os.WriteFile(runtimeConfig.KeyFilePathSingleSigner(testChainID), marshaled, 0o600) require.NoError(t, err) - err = os.WriteFile(runtimeConfig.KeyFilePathSingleSigner("different"), marshaled, 0600) + err = os.WriteFile(runtimeConfig.KeyFilePathSingleSigner("different"), marshaled, 0o600) require.NoError(t, err) validator := NewSingleSignerValidator(runtimeConfig) @@ -71,8 +69,10 @@ func TestSingleSignerValidator(t *testing.T) { // construct different block ID for proposal at same height as highest signed randHash := cometrand.Bytes(tmhash.Size) - blockID := cometproto.BlockID{Hash: randHash, - PartSetHeader: cometproto.PartSetHeader{Total: 5, Hash: randHash}} + blockID := cometproto.BlockID{ + Hash: randHash, + PartSetHeader: cometproto.PartSetHeader{Total: 5, Hash: randHash}, + } proposal = cometproto.Proposal{ Height: 1, @@ -123,5 +123,4 @@ func TestSingleSignerValidator(t *testing.T) { require.True(t, privateKey.PubKey().VerifySignature(block.VoteExtensionSignBytes, voteExtSig), "vote extension signature verification failed") - } diff --git a/signer/threshold_signer.go b/signer/threshold_signer.go index f8e9ef34..7c52c563 100644 --- a/signer/threshold_signer.go +++ b/signer/threshold_signer.go @@ -2,7 +2,7 @@ package signer import "time" -// Interface for the local signer whether it's a soft sign or HSM +// Interface for the local signer whether it's a soft sign or HSM. type ThresholdSigner interface { // PubKey returns the public key bytes for the combination of all cosigners. PubKey() []byte diff --git a/signer/threshold_validator.go b/signer/threshold_validator.go index e2120036..d9a11b75 100644 --- a/signer/threshold_validator.go +++ b/signer/threshold_validator.go @@ -10,13 +10,15 @@ import ( "sync" "time" - "github.com/cometbft/cometbft/libs/log" - cometrpcjsontypes "github.com/cometbft/cometbft/rpc/jsonrpc/types" "github.com/google/uuid" - "github.com/strangelove-ventures/horcrux/v3/signer/proto" "golang.org/x/sync/errgroup" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + + "github.com/cometbft/cometbft/libs/log" + cometrpcjsontypes "github.com/cometbft/cometbft/rpc/jsonrpc/types" + + "github.com/strangelove-ventures/horcrux/v3/signer/proto" ) var _ PrivValidator = &ThresholdValidator{} @@ -60,7 +62,7 @@ type ChainSignState struct { lastSignStateInitiatedMutex *sync.Mutex } -// NewThresholdValidator creates and returns a new ThresholdValidator +// NewThresholdValidator creates and returns a new ThresholdValidator. func NewThresholdValidator( logger log.Logger, config *RuntimeConfig, @@ -730,7 +732,6 @@ func (pv *ThresholdValidator) Sign( if err == nil && hasVoteExtensions { voteExtNonces, err = pv.nonceCache.GetNonces(cosignersForThisBlock) if err != nil { - u := uuid.New() var eg errgroup.Group var mu sync.Mutex @@ -965,7 +966,6 @@ func (pv *ThresholdValidator) Sign( css.lastSignStateMutex.Unlock() if err != nil { if _, isSameHRSError := err.(*SameHRSError); !isSameHRSError { - pv.notifyBlockSignError(chainID, block.HRSKey(), signBytes) return nil, nil, stamp, fmt.Errorf("error saving last sign state: %w", err) } diff --git a/signer/threshold_validator_test.go b/signer/threshold_validator_test.go index 22688fb1..6ff2e56e 100644 --- a/signer/threshold_validator_test.go +++ b/signer/threshold_validator_test.go @@ -7,12 +7,11 @@ import ( "crypto/sha256" "fmt" mrand "math/rand" + "os" "path/filepath" "sync" - "time" - - "os" "testing" + "time" cometcrypto "github.com/cometbft/cometbft/crypto" cometcryptoed25519 "github.com/cometbft/cometbft/crypto/ed25519" @@ -21,11 +20,6 @@ import ( cometrand "github.com/cometbft/cometbft/libs/rand" cometproto "github.com/cometbft/cometbft/proto/tendermint/types" comet "github.com/cometbft/cometbft/types" - "github.com/ethereum/go-ethereum/crypto/ecies" - "github.com/ethereum/go-ethereum/crypto/secp256k1" - "github.com/stretchr/testify/require" - tsed25519 "gitlab.com/unit410/threshold-ed25519/pkg" - "golang.org/x/sync/errgroup" ) func TestThresholdValidator2of2(t *testing.T) { @@ -61,7 +55,7 @@ func loadKeyForLocalCosigner( return err } - return os.WriteFile(cosigner.config.KeyFilePathCosigner(chainID), keyBz, 0600) + return os.WriteFile(cosigner.config.KeyFilePathCosigner(chainID), keyBz, 0o600) } func testThresholdValidator(t *testing.T, threshold, total uint8) { @@ -132,8 +126,10 @@ func testThresholdValidator(t *testing.T, threshold, total uint8) { // construct different block ID for proposal at same height as highest signed randHash := cometrand.Bytes(tmhash.Size) - blockID := cometproto.BlockID{Hash: randHash, - PartSetHeader: cometproto.PartSetHeader{Total: 5, Hash: randHash}} + blockID := cometproto.BlockID{ + Hash: randHash, + PartSetHeader: cometproto.PartSetHeader{Total: 5, Hash: randHash}, + } proposal = cometproto.Proposal{ Height: 1, @@ -368,7 +364,7 @@ func getTestLocalCosigners(t *testing.T, threshold, total uint8) ([]*LocalCosign for i := range pubKeys { cosignerDir := filepath.Join(tmpDir, fmt.Sprintf("cosigner_%d", i+1)) - err := os.MkdirAll(cosignerDir, 0777) + err := os.MkdirAll(cosignerDir, 0o777) require.NoError(t, err) cosignerConfig := &RuntimeConfig{ @@ -580,7 +576,7 @@ func testThresholdValidatorLeaderElection(t *testing.T, threshold, total uint8) // stagger signing requests with random sleep time.Sleep(time.Duration(mrand.Intn(50)+100) * time.Millisecond) //nolint:gosec - var extension = []byte{0x1, 0x2, 0x3} + extension := []byte{0x1, 0x2, 0x3} blockIDHash := sha256.New() blockIDHash.Write([]byte("something")) diff --git a/test/horcrux_test.go b/test/horcrux_test.go index 5a62bf35..5bdcc5d7 100644 --- a/test/horcrux_test.go +++ b/test/horcrux_test.go @@ -375,7 +375,6 @@ func TestMultipleChainHorcrux(t *testing.T) { chainConfig := chainConfig preGenesises[i] = func(cw *chainWrapper) func(ibc.ChainConfig) error { return func(cc ibc.ChainConfig) error { - firstSentry := cw.chain.Validators[0] sentries := append(cosmos.ChainNodes{firstSentry}, cw.chain.FullNodes...) @@ -613,7 +612,6 @@ func TestHorcruxProxyGRPC(t *testing.T) { chainConfig := chainConfig preGenesises[i] = func(cw *chainWrapper) func(ibc.ChainConfig) error { return func(cc ibc.ChainConfig) error { - firstSentry := cw.chain.Validators[0] sentries := append(cosmos.ChainNodes{firstSentry}, cw.chain.FullNodes...) diff --git a/test/validator_single.go b/test/validator_single.go index 13396712..8ce9485d 100644 --- a/test/validator_single.go +++ b/test/validator_single.go @@ -65,7 +65,8 @@ func preGenesisSingleNodeAndHorcruxSingle( logger *zap.Logger, client *client.Client, network string, - pubKey *crypto.PubKey) func(*chainWrapper) func(ibc.ChainConfig) error { + pubKey *crypto.PubKey, +) func(*chainWrapper) func(ibc.ChainConfig) error { return func(cw *chainWrapper) func(ibc.ChainConfig) error { return func(cc ibc.ChainConfig) error { horcruxValidator := cw.chain.Validators[0] diff --git a/test/validator_threshold.go b/test/validator_threshold.go index bff4928d..832bf740 100644 --- a/test/validator_threshold.go +++ b/test/validator_threshold.go @@ -84,7 +84,8 @@ func preGenesisSingleNodeAndHorcruxThreshold( totalSigners int, // total number of signers for the single horcrux validator threshold uint8, // key shard threshold, and therefore how many horcrux signers must participate to sign a block sentriesPerSigner int, // how many sentries should each horcrux signer connect to (min: 1, max: totalSentries) - pubKey *crypto.PubKey) func(*chainWrapper) func(ibc.ChainConfig) error { + pubKey *crypto.PubKey, +) func(*chainWrapper) func(ibc.ChainConfig) error { return func(cw *chainWrapper) func(ibc.ChainConfig) error { return func(cc ibc.ChainConfig) error { horcruxValidator := cw.chain.Validators[0] @@ -124,7 +125,8 @@ func preGenesisAllHorcruxThreshold( sentriesPerValidator int, // how many sentries for each horcrux validator (min: sentriesPerSigner, max: totalSentries) sentriesPerSigner int, // how many sentries should each horcrux signer connect to (min: 1, max: sentriesPerValidator) - pubKeys []crypto.PubKey) func(*chainWrapper) func(ibc.ChainConfig) error { + pubKeys []crypto.PubKey, +) func(*chainWrapper) func(ibc.ChainConfig) error { return func(cw *chainWrapper) func(ibc.ChainConfig) error { return func(cc ibc.ChainConfig) error { fnsPerVal := sentriesPerValidator - 1 // minus 1 for the validator itself @@ -146,7 +148,6 @@ func preGenesisAllHorcruxThreshold( sentries, sentriesPerSigner, ) - if err != nil { return err } @@ -366,6 +367,7 @@ func getSentriesForCosignerConnection(sentries cosmos.ChainNodes, numSigners int } return peers } + func getCosignerMetrics(ctx context.Context, cosigners cosmos.SidecarProcesses) { for _, s := range cosigners { s := s @@ -390,15 +392,12 @@ func getCosignerMetrics(ctx context.Context, cosigners cosmos.SidecarProcesses) } func getMetrics(ctx context.Context, cosigner *cosmos.SidecarProcess) (map[string]*dto.MetricFamily, error) { - debugAddr, err := cosigner.GetHostPorts(ctx, debugPortDocker) if err != nil { return nil, err } req, err := http.NewRequestWithContext(ctx, "GET", "http://"+debugAddr[0]+"/metrics", nil) - if err != nil { - return nil, err } resp, err := http.DefaultClient.Do(req) @@ -410,7 +409,6 @@ func getMetrics(ctx context.Context, cosigner *cosmos.SidecarProcess) (map[strin var parser expfmt.TextParser mf, err := parser.TextToMetricFamilies(resp.Body) if err != nil { - return nil, err } From a47a77e4be334b6435d7924cff81701f78495ca8 Mon Sep 17 00:00:00 2001 From: Justin Tieri <37750742+jtieri@users.noreply.github.com> Date: Wed, 21 Aug 2024 14:23:25 -0500 Subject: [PATCH 05/14] chore: fix broken imports after gofumpt --- signer/single_signer_validator_test.go | 1 + signer/threshold_validator_test.go | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/signer/single_signer_validator_test.go b/signer/single_signer_validator_test.go index 7139a50c..2db40e9c 100644 --- a/signer/single_signer_validator_test.go +++ b/signer/single_signer_validator_test.go @@ -13,6 +13,7 @@ import ( cometrand "github.com/cometbft/cometbft/libs/rand" cometprivval "github.com/cometbft/cometbft/privval" cometproto "github.com/cometbft/cometbft/proto/tendermint/types" + "github.com/stretchr/testify/require" ) func TestSingleSignerValidator(t *testing.T) { diff --git a/signer/threshold_validator_test.go b/signer/threshold_validator_test.go index 6ff2e56e..c70d0ff4 100644 --- a/signer/threshold_validator_test.go +++ b/signer/threshold_validator_test.go @@ -20,6 +20,11 @@ import ( cometrand "github.com/cometbft/cometbft/libs/rand" cometproto "github.com/cometbft/cometbft/proto/tendermint/types" comet "github.com/cometbft/cometbft/types" + "github.com/ethereum/go-ethereum/crypto/ecies" + "github.com/ethereum/go-ethereum/crypto/secp256k1" + "github.com/stretchr/testify/require" + tsed25519 "gitlab.com/unit410/threshold-ed25519/pkg" + "golang.org/x/sync/errgroup" ) func TestThresholdValidator2of2(t *testing.T) { From 46f8265e471552135213e392772f247f997254e4 Mon Sep 17 00:00:00 2001 From: Justin Tieri <37750742+jtieri@users.noreply.github.com> Date: Thu, 22 Aug 2024 10:56:42 -0500 Subject: [PATCH 06/14] docs: fix broken links in README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ca2eccec..6ca750f9 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Horcrux is a [multi-party-computation (MPC)](https://en.wikipedia.org/wiki/Secur Take your validator infrastructure to the next level of security and availability -- Composed of a cluster of signer nodes in place of the [remote signer](https://docs.tendermint.com/master/nodes/remote-signer.html), enabling High Availability (HA) for block signing through fault tolerance. +- Composed of a cluster of signer nodes in place of the [remote signer](https://docs.tendermint.com/v0.34/tools/remote-signer-validation.html), enabling High Availability (HA) for block signing through fault tolerance. - Secure your validator private key by splitting it across multiple private signer nodes using threshold Ed25519 signatures - Add security and availability without sacrificing block sign performance. @@ -54,8 +54,8 @@ software or this license, under any kind of legal claim. ## References -- [CometBFT Validator Documentation](https://docs.cometbft.com/main/core/validators) -- [Cosmos Hub Validator Documentation](https://hub.cosmos.network/master/validators/overview.html) +- [CometBFT Validator Documentation](https://docs.cometbft.com/v0.38/core/validators) +- [Cosmos Hub Validator Documentation](https://hub.cosmos.network/main/validators/overview.html) - [Provably Secure Distributed Schnorr Signatures and a (t, n) Threshold Scheme for Implicit Certificates](http://cacr.uwaterloo.ca/techreports/2001/corr2001-13.ps) ## Acknowledgement From c11c70ac15c14ddd8e9900e0490ed177e1e42d45 Mon Sep 17 00:00:00 2001 From: Justin Tieri <37750742+jtieri@users.noreply.github.com> Date: Thu, 22 Aug 2024 10:58:13 -0500 Subject: [PATCH 07/14] ci: update golangci.yml file Add back the importas linter since it seemed to be used still. Remove dogsled configuration since we no longer use it. Disable the float-compare rule in testifylint because it is not helpful in the few cases we do float comparisons in tests. --- .golangci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index c18569cf..ea1c5212 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -29,6 +29,7 @@ linters: - gosmopolitan - govet - grouper + - importas - ineffassign - loggercheck - misspell @@ -65,8 +66,6 @@ linters-settings: gosec: excludes: - G404 # disables checks on insecure random number source - dogsled: - max-blank-identifiers: 3 importas: no-extra-aliases: true alias: @@ -140,6 +139,9 @@ linters-settings: alias: boltdb - pkg: math/rand alias: mrand + testifylint: + disable: + - float-compare issues: max-issues-per-linter: 0 From 4b8318771d3aba67ae45acaf0f8a5eeaca09a642 Mon Sep 17 00:00:00 2001 From: Justin Tieri <37750742+jtieri@users.noreply.github.com> Date: Thu, 22 Aug 2024 11:07:22 -0500 Subject: [PATCH 08/14] docs: remove unnecessary link in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6ca750f9..aae78912 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Horcrux is a [multi-party-computation (MPC)](https://en.wikipedia.org/wiki/Secur Take your validator infrastructure to the next level of security and availability -- Composed of a cluster of signer nodes in place of the [remote signer](https://docs.tendermint.com/v0.34/tools/remote-signer-validation.html), enabling High Availability (HA) for block signing through fault tolerance. +- Composed of a cluster of signer nodes in place of the remote signer, enabling High Availability (HA) for block signing through fault tolerance. - Secure your validator private key by splitting it across multiple private signer nodes using threshold Ed25519 signatures - Add security and availability without sacrificing block sign performance. From 37206d13ea62e1bbd04cc353a1863ead16a01db0 Mon Sep 17 00:00:00 2001 From: Justin Tieri <37750742+jtieri@users.noreply.github.com> Date: Mon, 28 Oct 2024 11:56:39 -0500 Subject: [PATCH 09/14] chore: update .golangci.yml --- .golangci.yml | 85 +++------------------------------------------------ 1 file changed, 4 insertions(+), 81 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index ea1c5212..d3752d23 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -10,6 +10,7 @@ linters: - asciicheck - bidichk - bodyclose + - copyloopvar - decorder - dupl - dupword @@ -17,8 +18,7 @@ linters: - errchkjson - errname - exhaustive - - exportloopref - - forbidigo + # - forbidigo disabled because there are many places in cmd where passing in a logger would require non-trivial refactor - gci - goconst - gocritic @@ -29,7 +29,6 @@ linters: - gosmopolitan - govet - grouper - - importas - ineffassign - loggercheck - misspell @@ -61,87 +60,11 @@ linters-settings: - prefix(github.com/cosmos) - prefix(github.com/cosmos/cosmos-sdk) - prefix(github.com/cometbft/cometbft) - # TODO: Replace below with '- prefix()' - prefix(github.com/strangelove-ventures/horcrux) gosec: excludes: - G404 # disables checks on insecure random number source - importas: - no-extra-aliases: true - alias: - - pkg: github.com/cosmos/cosmos-sdk/crypto/codec - alias: cryptocodec - - pkg: github.com/cosmos/cosmos-sdk/crypto/types - alias: cryptotypes - - pkg: github.com/cosmos/cosmos-sdk/x/slashing/types - alias: slashingtypes - - pkg: github.com/cometbft/cometbft/types - alias: comet - - pkg: github.com/cometbft/cometbft/config - alias: cometconfig - - pkg: github.com/cometbft/cometbft/crypto - alias: cometcrypto - - pkg: github.com/cometbft/cometbft/crypto/ed25519 - alias: cometcryptoed25519 - - pkg: github.com/cometbft/cometbft/crypto/encoding - alias: cometcryptoencoding - - pkg: github.com/tendermint/go-amino - alias: amino - - pkg: github.com/cometbft/cometbft/libs/bytes - alias: cometbytes - - pkg: github.com/cometbft/cometbft/libs/json - alias: cometjson - - pkg: github.com/cometbft/cometbft/libs/log - alias: cometlog - - pkg: github.com/cometbft/cometbft/libs/net - alias: cometnet - - pkg: github.com/cometbft/cometbft/libs/os - alias: cometos - - pkg: github.com/cometbft/cometbft/libs/rand - alias: cometrand - - pkg: github.com/cometbft/cometbft/libs/service - alias: cometservice - - pkg: github.com/cometbft/cometbft/p2p/conn - alias: cometp2pconn - - pkg: github.com/cometbft/cometbft/privval - alias: cometprivval - - pkg: github.com/cometbft/cometbft/proto/tendermint/types - alias: cometproto - - pkg: github.com/cometbft/cometbft/proto/tendermint/crypto - alias: cometprotocrypto - - pkg: github.com/cometbft/cometbft/proto/tendermint/privval - alias: cometprotoprivval - - pkg: github.com/cometbft/cometbft/rpc/client - alias: cometrpcclient - - pkg: github.com/cometbft/cometbft/rpc/client/http - alias: cometrpchttp - - pkg: github.com/cometbft/cometbft/rpc/jsonrpc/client - alias: cometrpcjsonclient - - pkg: github.com/cometbft/cometbft/rpc/jsonrpc/types - alias: cometrpcjsontypes - - pkg: github.com/cometbft/cometbft/rpc/core/types - alias: cometrpctypes - - pkg: github.com/ecies/go/v2 - alias: ecies - - pkg: github.com/grpc-ecosystem/go-grpc-middleware/retry - alias: grpcretry - - pkg : github.com/kraken-hpc/go-fork - alias: fork - - pkg: github.com/armon/go-metrics/prometheus - alias: gmprometheus - - pkg: github.com/mitchellh/go-homedir - alias: homedir - - pkg: gitlab.com/unit410/threshold-ed25519/pkg - alias: tsed25519 - - pkg: github.com/Jille/raft-grpc-transport - alias: raftgrpctransport - - pkg: github.com/hashicorp/raft-boltdb/v2 - alias: boltdb - - pkg: math/rand - alias: mrand - testifylint: - disable: - - float-compare + - G115 # disables checks on type conversions between signed and unsigned integers issues: - max-issues-per-linter: 0 + max-issues-per-linter: 0 \ No newline at end of file From 167408bdc32ed6077ab044a0e490026c361a54b8 Mon Sep 17 00:00:00 2001 From: Justin Tieri <37750742+jtieri@users.noreply.github.com> Date: Mon, 28 Oct 2024 11:57:00 -0500 Subject: [PATCH 10/14] build: update Go version to 1.23 --- go.mod | 2 +- go.work | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index d0d48e3c..a76cf95b 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/strangelove-ventures/horcrux/v3 -go 1.21 +go 1.23 require ( github.com/Jille/raft-grpc-leader-rpc v1.1.0 diff --git a/go.work b/go.work index 1519011f..d889c81b 100644 --- a/go.work +++ b/go.work @@ -1,4 +1,4 @@ -go 1.21 +go 1.23 use ( . From 3628b425f0b4446a34f0f4dc235b3546ba56c363 Mon Sep 17 00:00:00 2001 From: Justin Tieri <37750742+jtieri@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:01:47 -0500 Subject: [PATCH 11/14] chore: fix linter warnings --- cmd/horcrux/cmd/shards.go | 4 ++++ signer/cond/cond_test.go | 4 ++-- signer/cosigner_key_shares.go | 2 -- signer/cosigner_nonce_cache.go | 2 -- signer/cosigner_nonce_cache_test.go | 25 ++++++++++++------------ signer/cosigner_security_ecies_test.go | 6 ++---- signer/cosigner_security_rsa_test.go | 4 ---- signer/local_cosigner.go | 9 --------- signer/local_cosigner_test.go | 4 ++++ signer/services.go | 10 ++++++---- signer/services_test.go | 4 ++-- signer/sign_state.go | 8 ++++++++ signer/single_signer_validator_test.go | 3 ++- signer/threshold_validator.go | 2 -- signer/threshold_validator_test.go | 27 +++++++++++++++----------- 15 files changed, 59 insertions(+), 55 deletions(-) diff --git a/cmd/horcrux/cmd/shards.go b/cmd/horcrux/cmd/shards.go index f34c5792..2dde3d19 100644 --- a/cmd/horcrux/cmd/shards.go +++ b/cmd/horcrux/cmd/shards.go @@ -158,6 +158,8 @@ func createCosignerEd25519ShardsCmd() *cobra.Command { } // createCosignerECIESShardsCmd is a cobra command for creating cosigner-to-cosigner encryption secp256k1 keys. +// +//nolint:dupl func createCosignerECIESShardsCmd() *cobra.Command { cmd := &cobra.Command{ Use: "create-ecies-shards", @@ -206,6 +208,8 @@ func createCosignerECIESShardsCmd() *cobra.Command { } // createCosignerRSAShardsCmd is a cobra command for creating cosigner-to-cosigner encryption RSA keys. +// +//nolint:dupl func createCosignerRSAShardsCmd() *cobra.Command { cmd := &cobra.Command{ Use: "create-rsa-shards", diff --git a/signer/cond/cond_test.go b/signer/cond/cond_test.go index db7dc90f..e62a6884 100644 --- a/signer/cond/cond_test.go +++ b/signer/cond/cond_test.go @@ -18,7 +18,7 @@ func TestRace(t *testing.T) { c.L.Lock() x = 1 c.Wait() - require.Equal(t, 2, x) + require.Equal(t, 2, x) //nolint:testifylint // go-require x = 3 c.Broadcast() c.L.Unlock() @@ -44,7 +44,7 @@ func TestRace(t *testing.T) { for { if x == 2 { c.Wait() - require.Equal(t, 3, x) + require.Equal(t, 3, x) //nolint:testifylint // go-require break } if x == 3 { diff --git a/signer/cosigner_key_shares.go b/signer/cosigner_key_shares.go index 54dcb114..50778b59 100644 --- a/signer/cosigner_key_shares.go +++ b/signer/cosigner_key_shares.go @@ -117,7 +117,6 @@ func makeRSAKeys(num int) (rsaKeys []*rsa.PrivateKey, pubKeys []*rsa.PublicKey, var eg errgroup.Group bitSize := 4096 for i := 0; i < num; i++ { - i := i eg.Go(func() error { rsaKey, err := rsa.GenerateKey(rand.Reader, bitSize) if err != nil { @@ -137,7 +136,6 @@ func makeECIESKeys(num int) ([]*ecies.PrivateKey, []*ecies.PublicKey, error) { pubKeys := make([]*ecies.PublicKey, num) var eg errgroup.Group for i := 0; i < num; i++ { - i := i eg.Go(func() error { eciesKey, err := ecies.GenerateKey(rand.Reader, secp256k1.S256(), nil) if err != nil { diff --git a/signer/cosigner_nonce_cache.go b/signer/cosigner_nonce_cache.go index 598166ed..c8d638ba 100644 --- a/signer/cosigner_nonce_cache.go +++ b/signer/cosigner_nonce_cache.go @@ -278,8 +278,6 @@ func (cnc *CosignerNonceCache) LoadN(ctx context.Context, n int) { expiration := time.Now().Add(cnc.nonceExpiration) for i, p := range cnc.cosigners { - i := i - p := p go func() { defer wg.Done() ctx, cancel := context.WithTimeout(ctx, cnc.getNoncesTimeout) diff --git a/signer/cosigner_nonce_cache_test.go b/signer/cosigner_nonce_cache_test.go index 91fb3c85..f0e724b1 100644 --- a/signer/cosigner_nonce_cache_test.go +++ b/signer/cosigner_nonce_cache_test.go @@ -28,32 +28,32 @@ func TestMovingAverage(t *testing.T) { ma.add(3*time.Second, 500) require.Len(t, ma.items, 1) - require.Equal(t, float64(500), ma.average()) + require.InEpsilon(t, float64(500), ma.average(), 0) ma.add(3*time.Second, 100) require.Len(t, ma.items, 2) - require.Equal(t, float64(300), ma.average()) + require.InEpsilon(t, float64(300), ma.average(), 0) ma.add(6*time.Second, 600) require.Len(t, ma.items, 3) - require.Equal(t, float64(450), ma.average()) + require.InEpsilon(t, float64(450), ma.average(), 0) // should kick out the first one ma.add(3*time.Second, 500) require.Len(t, ma.items, 3) - require.Equal(t, float64(450), ma.average()) + require.InEpsilon(t, float64(450), ma.average(), 0) // should kick out the second one ma.add(6*time.Second, 500) require.Len(t, ma.items, 3) - require.Equal(t, float64(540), ma.average()) + require.InEpsilon(t, float64(540), ma.average(), 0) for i := 0; i < 5; i++ { ma.add(2500*time.Millisecond, 1000) } require.Len(t, ma.items, 5) - require.Equal(t, float64(1000), ma.average()) + require.InEpsilon(t, float64(1000), ma.average(), 0) } func TestClearNonces(t *testing.T) { @@ -173,12 +173,12 @@ func TestNonceCacheDemand(t *testing.T) { _, err := nonceCache.GetNonces([]Cosigner{cosigners[0], cosigners[1]}) require.NoError(t, err) time.Sleep(10 * time.Millisecond) - require.Greater(t, nonceCache.cache.Size(), 0) + require.Positive(t, nonceCache.cache.Size()) } size := nonceCache.cache.Size() - require.Greater(t, size, 0) + require.Positive(t, size) cancel() @@ -186,7 +186,7 @@ func TestNonceCacheDemand(t *testing.T) { count, pruned := mp.Result() - require.Greater(t, count, 0, "count of pruning calls must be greater than 0") + require.Positive(t, count, "count of pruning calls must be greater than 0") require.Equal(t, 0, pruned, "no nonces should have been pruned") } @@ -218,6 +218,7 @@ func TestNonceCacheExpiration(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) const loadN = 100 + // Load first set of 100 nonces nonceCache.LoadN(ctx, loadN) @@ -240,7 +241,7 @@ func TestNonceCacheExpiration(t *testing.T) { // we should have pruned only the first set of nonces // The second set of nonces should not have expired yet and we should not have load any more - require.Equal(t, pruned, loadN) + require.Equal(t, loadN, pruned) cancel() @@ -425,7 +426,7 @@ func TestNonceCacheDemandSlow(t *testing.T) { for i := 0; i < 10; i++ { time.Sleep(200 * time.Millisecond) - require.Greater(t, nonceCache.cache.Size(), 0) + require.Positive(t, nonceCache.cache.Size()) _, err := nonceCache.GetNonces([]Cosigner{cosigners[0], cosigners[1]}) require.NoError(t, err) } @@ -462,7 +463,7 @@ func TestNonceCacheDemandSlowDefault(t *testing.T) { for i := 0; i < 10; i++ { time.Sleep(7 * time.Second) - require.Greater(t, nonceCache.cache.Size(), 0) + require.Positive(t, nonceCache.cache.Size()) _, err := nonceCache.GetNonces([]Cosigner{cosigners[0], cosigners[1]}) require.NoError(t, err) } diff --git a/signer/cosigner_security_ecies_test.go b/signer/cosigner_security_ecies_test.go index aa7d04d8..357fe46a 100644 --- a/signer/cosigner_security_ecies_test.go +++ b/signer/cosigner_security_ecies_test.go @@ -56,6 +56,8 @@ func TestCosignerECIES(t *testing.T) { } func testCosignerSecurity(t *testing.T, securities []CosignerSecurity) error { + t.Helper() + var ( mockPub = []byte("mock_pub") mockShare = []byte("mock_share") @@ -104,16 +106,12 @@ func TestConcurrentIterateCosignerECIES(t *testing.T) { for i := 0; i < 5000; i++ { var eg errgroup.Group for i, security := range securities { - security := security - i := i eg.Go(func() error { var nestedEg errgroup.Group for j, security2 := range securities { if i == j { continue } - security2 := security2 - j := j nestedEg.Go(func() error { n, err := security.EncryptAndSign(j+1, []byte("mock_pub"), []byte("mock_share")) if err != nil { diff --git a/signer/cosigner_security_rsa_test.go b/signer/cosigner_security_rsa_test.go index 7830d9af..72a16862 100644 --- a/signer/cosigner_security_rsa_test.go +++ b/signer/cosigner_security_rsa_test.go @@ -80,16 +80,12 @@ func TestConcurrentIterateCosignerRSA(t *testing.T) { for i := 0; i < 100; i++ { var eg errgroup.Group for i, security := range securities { - security := security - i := i eg.Go(func() error { var nestedEg errgroup.Group for j, security2 := range securities { if i == j { continue } - security2 := security2 - j := j nestedEg.Go(func() error { n, err := security.EncryptAndSign(j+1, []byte("mock_pub"), []byte("mock_share")) if err != nil { diff --git a/signer/local_cosigner.go b/signer/local_cosigner.go index 602efe6e..1114c958 100644 --- a/signer/local_cosigner.go +++ b/signer/local_cosigner.go @@ -368,9 +368,6 @@ func (cosigner *LocalCosigner) GetNonces( // so we perform these operations in parallel. for j, u := range uuids { - j := j - u := u - outerEg.Go(func() error { meta, err := cosigner.generateNoncesIfNecessary(u) if err != nil { @@ -387,8 +384,6 @@ func (cosigner *LocalCosigner) GetNonces( continue } - i := i - eg.Go(func() error { secretPart, err := cosigner.getNonce(meta, peerID) @@ -522,8 +517,6 @@ func (cosigner *LocalCosigner) SetNoncesAndSign( // so we perform these operations in parallel. for _, secretPart := range req.Nonces.Nonces { - secretPart := secretPart - eg.Go(func() error { return cosigner.setNonce(req.Nonces.UUID, secretPart) }) @@ -531,8 +524,6 @@ func (cosigner *LocalCosigner) SetNoncesAndSign( if req.VoteExtensionNonces != nil { for _, secretPart := range req.VoteExtensionNonces.Nonces { - secretPart := secretPart - eg.Go(func() error { return cosigner.setNonce(req.VoteExtensionNonces.UUID, secretPart) }) diff --git a/signer/local_cosigner_test.go b/signer/local_cosigner_test.go index adeacd7e..4a915257 100644 --- a/signer/local_cosigner_test.go +++ b/signer/local_cosigner_test.go @@ -37,6 +37,7 @@ func TestLocalCosignerSignRSA3of5(t *testing.T) { } func testLocalCosignerSignRSA(t *testing.T, threshold, total uint8) { + t.Helper() t.Parallel() security := make([]CosignerSecurity, total) @@ -73,6 +74,7 @@ func TestLocalCosignerSignECIES3of5(t *testing.T) { } func testLocalCosignerSignECIES(t *testing.T, threshold, total uint8) { + t.Helper() t.Parallel() security := make([]CosignerSecurity, total) @@ -101,6 +103,8 @@ func testLocalCosignerSignECIES(t *testing.T, threshold, total uint8) { } func testLocalCosignerSign(t *testing.T, threshold, total uint8, security []CosignerSecurity) { + t.Helper() + privateKey := cometcryptoed25519.GenPrivKey() privKeyBytes := [64]byte{} diff --git a/signer/services.go b/signer/services.go index d649717d..f2ded9d6 100644 --- a/signer/services.go +++ b/signer/services.go @@ -61,14 +61,16 @@ func RequireNotRunning(log cometlog.Logger, pidFilePath string) error { return nil } - errno, ok := err.(syscall.Errno) + var errno syscall.Errno + ok := errors.As(err, &errno) if !ok { return fmt.Errorf("unexpected error type from signaling horcrux PID: %d", pid) } - switch errno { - case syscall.ESRCH: + + switch { + case errors.Is(errno, syscall.ESRCH): return fmt.Errorf("search error while signaling horcrux PID: %d", pid) - case syscall.EPERM: + case errors.Is(errno, syscall.EPERM): return fmt.Errorf("permission denied accessing horcrux PID: %d", pid) } return fmt.Errorf("unexpected error while signaling horcrux PID: %d", pid) diff --git a/signer/services_test.go b/signer/services_test.go index f4d92143..ab84bec0 100644 --- a/signer/services_test.go +++ b/signer/services_test.go @@ -12,7 +12,7 @@ import ( "testing" "time" - fork "github.com/kraken-hpc/go-fork" + "github.com/kraken-hpc/go-fork" "github.com/stretchr/testify/require" cometlog "github.com/cometbft/cometbft/libs/log" @@ -131,7 +131,7 @@ func TestIsRunningNonExistentPid(t *testing.T) { require.NoError(t, err, "error writing pid file") err = signer.RequireNotRunning(cometlog.NewNopLogger(), pidFilePath) - require.Nil(t, err) + require.NoError(t, err) _, err = os.Stat(pidFilePath) require.ErrorIs(t, err, os.ErrNotExist) diff --git a/signer/sign_state.go b/signer/sign_state.go index 3e712a00..8932d6a0 100644 --- a/signer/sign_state.go +++ b/signer/sign_state.go @@ -46,6 +46,10 @@ func CanonicalVoteToStep(vote *cometproto.CanonicalVote) int8 { return stepPrevote case cometproto.PrecommitType: return stepPrecommit + case cometproto.ProposalType: + panic("Invalid vote type") + case cometproto.UnknownType: + panic("Unknown vote type") default: panic("Unknown vote type") } @@ -57,6 +61,10 @@ func VoteToStep(vote *cometproto.Vote) int8 { return stepPrevote case cometproto.PrecommitType: return stepPrecommit + case cometproto.ProposalType: + panic("Invalid vote type") + case cometproto.UnknownType: + panic("Unknown vote type") default: panic("Unknown vote type") } diff --git a/signer/single_signer_validator_test.go b/signer/single_signer_validator_test.go index 2db40e9c..e609c05e 100644 --- a/signer/single_signer_validator_test.go +++ b/signer/single_signer_validator_test.go @@ -7,13 +7,14 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + cometcryptoed25519 "github.com/cometbft/cometbft/crypto/ed25519" "github.com/cometbft/cometbft/crypto/tmhash" cometjson "github.com/cometbft/cometbft/libs/json" cometrand "github.com/cometbft/cometbft/libs/rand" cometprivval "github.com/cometbft/cometbft/privval" cometproto "github.com/cometbft/cometbft/proto/tendermint/types" - "github.com/stretchr/testify/require" ) func TestSingleSignerValidator(t *testing.T) { diff --git a/signer/threshold_validator.go b/signer/threshold_validator.go index d9a11b75..746dc239 100644 --- a/signer/threshold_validator.go +++ b/signer/threshold_validator.go @@ -736,7 +736,6 @@ func (pv *ThresholdValidator) Sign( var eg errgroup.Group var mu sync.Mutex for _, c := range cosignersForThisBlock { - c := c eg.Go(func() error { nonces, err := c.GetNonces(ctx, []uuid.UUID{u}) if err != nil { @@ -792,7 +791,6 @@ func (pv *ThresholdValidator) Sign( var eg errgroup.Group for _, cosigner := range cosignersForThisBlock { - cosigner := cosigner eg.Go(func() error { for cosigner != nil { signCtx, cancel := context.WithTimeout(ctx, pv.grpcTimeout) diff --git a/signer/threshold_validator_test.go b/signer/threshold_validator_test.go index c70d0ff4..3588aeaf 100644 --- a/signer/threshold_validator_test.go +++ b/signer/threshold_validator_test.go @@ -13,6 +13,12 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/crypto/ecies" + "github.com/ethereum/go-ethereum/crypto/secp256k1" + "github.com/stretchr/testify/require" + tsed25519 "gitlab.com/unit410/threshold-ed25519/pkg" + "golang.org/x/sync/errgroup" + cometcrypto "github.com/cometbft/cometbft/crypto" cometcryptoed25519 "github.com/cometbft/cometbft/crypto/ed25519" "github.com/cometbft/cometbft/crypto/tmhash" @@ -20,11 +26,6 @@ import ( cometrand "github.com/cometbft/cometbft/libs/rand" cometproto "github.com/cometbft/cometbft/proto/tendermint/types" comet "github.com/cometbft/cometbft/types" - "github.com/ethereum/go-ethereum/crypto/ecies" - "github.com/ethereum/go-ethereum/crypto/secp256k1" - "github.com/stretchr/testify/require" - tsed25519 "gitlab.com/unit410/threshold-ed25519/pkg" - "golang.org/x/sync/errgroup" ) func TestThresholdValidator2of2(t *testing.T) { @@ -64,6 +65,8 @@ func loadKeyForLocalCosigner( } func testThresholdValidator(t *testing.T, threshold, total uint8) { + t.Helper() + cosigners, pubKey := getTestLocalCosigners(t, threshold, total) thresholdCosigners := make([]Cosigner, 0, threshold-1) @@ -340,6 +343,8 @@ func testThresholdValidator(t *testing.T, threshold, total uint8) { } func getTestLocalCosigners(t *testing.T, threshold, total uint8) ([]*LocalCosigner, cometcrypto.PubKey) { + t.Helper() + eciesKeys := make([]*ecies.PrivateKey, total) pubKeys := make([]*ecies.PublicKey, total) cosigners := make([]*LocalCosigner, total) @@ -410,6 +415,8 @@ func getTestLocalCosigners(t *testing.T, threshold, total uint8) ([]*LocalCosign } func testThresholdValidatorLeaderElection(t *testing.T, threshold, total uint8) { + t.Helper() + cosigners, pubKey := getTestLocalCosigners(t, threshold, total) thresholdValidators := make([]*ThresholdValidator, 0, total) @@ -487,9 +494,9 @@ func testThresholdValidatorLeaderElection(t *testing.T, threshold, total uint8) wg.Add(len(thresholdValidators)) var mu sync.Mutex success := false - for _, tv := range thresholdValidators { - tv := tv + //nolint:dupl + for _, tv := range thresholdValidators { tv.nonceCache.LoadN(ctx, 1) go func() { @@ -529,9 +536,9 @@ func testThresholdValidatorLeaderElection(t *testing.T, threshold, total uint8) require.True(t, success) // at least one should succeed so that the block is not missed. wg.Add(len(thresholdValidators)) success = false - for _, tv := range thresholdValidators { - tv := tv + //nolint:dupl + for _, tv := range thresholdValidators { tv.nonceCache.LoadN(ctx, 1) go func() { @@ -572,8 +579,6 @@ func testThresholdValidatorLeaderElection(t *testing.T, threshold, total uint8) wg.Add(len(thresholdValidators)) success = false for _, tv := range thresholdValidators { - tv := tv - tv.nonceCache.LoadN(ctx, 2) go func() { From 64b6805db270b1655a9cf9c5026dc4bdf3a28d0c Mon Sep 17 00:00:00 2001 From: Justin Tieri <37750742+jtieri@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:05:37 -0500 Subject: [PATCH 12/14] chore: update Dockerfiles to use Go 1.23 --- docker/horcrux/Dockerfile | 2 +- docker/horcrux/native.Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/horcrux/Dockerfile b/docker/horcrux/Dockerfile index 5db8717d..543a7048 100644 --- a/docker/horcrux/Dockerfile +++ b/docker/horcrux/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=$BUILDPLATFORM golang:1.21-alpine AS build-env +FROM --platform=$BUILDPLATFORM golang:1.23-alpine AS build-env RUN apk add --update --no-cache curl make git libc-dev bash gcc linux-headers eudev-dev diff --git a/docker/horcrux/native.Dockerfile b/docker/horcrux/native.Dockerfile index 843dca44..b89fe5fe 100644 --- a/docker/horcrux/native.Dockerfile +++ b/docker/horcrux/native.Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.21-alpine AS build-env +FROM golang:1.23-alpine AS build-env RUN apk add --update --no-cache curl make git libc-dev bash gcc linux-headers eudev-dev From 441a9ff538824a40fef747f2d2afe24d55ec7b9e Mon Sep 17 00:00:00 2001 From: Justin Tieri <37750742+jtieri@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:05:49 -0500 Subject: [PATCH 13/14] ci: update CI to use Go 1.23 --- .github/workflows/lint.yml | 2 +- .github/workflows/tests.yml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 47c14445..d3e7bcc0 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -14,7 +14,7 @@ permissions: contents: read env: - GO_VERSION: 1.21 + GO_VERSION: 1.23 jobs: golangci: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 09dfa872..5c0585a8 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,10 +17,10 @@ jobs: runs-on: ubuntu-latest steps: # Install and setup go - - name: Set up Go 1.21 + - name: Set up Go 1.23 uses: actions/setup-go@v4 with: - go-version: '^1.21.4' + go-version: '^1.23' # checkout horcrux - name: checkout horcrux @@ -47,10 +47,10 @@ jobs: - TestHorcruxProxyGRPC steps: # Install and setup go - - name: Set up Go 1.21 + - name: Set up Go 1.23 uses: actions/setup-go@v4 with: - go-version: '^1.21.4' + go-version: '^1.23' # checkout horcrux - name: checkout horcrux From 0aaef9a847e1b950ce13c93d6bbf8bb8eb2f278e Mon Sep 17 00:00:00 2001 From: Justin Tieri <37750742+jtieri@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:14:54 -0500 Subject: [PATCH 14/14] ci: update golangci-lint version in lint.yml --- .github/workflows/lint.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index d3e7bcc0..d54532c6 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -28,7 +28,7 @@ jobs: - uses: actions/checkout@v4 - name: golangci-lint - uses: golangci/golangci-lint-action@v6.1.0 + uses: golangci/golangci-lint-action@v6.1.1 with: - version: v1.57.2 + version: v1.61.0 args: --timeout 15m \ No newline at end of file