Fix finalization voting combining#2012
Conversation
There was a problem hiding this comment.
Pull request overview
Adds deterministic finality / generator-commitment functionality across node API, client SDK, and crypto primitives, plus supporting tests and tooling adjustments.
Changes:
- Introduces BLS (CIRCL) signing utilities + PoP (proof-of-possession) helpers and tests.
- Adds P-256 signature verification and X.509 certificate/CRL parsing + tests and fixtures.
- Extends REST API + client with finalization endpoints, generator queries, and
/transactions/signfor CommitToGeneration.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/crypto/testdata/tdx-crl.pem | Adds CRL fixtures for certificate validation tests |
| pkg/crypto/testdata/tdx-cert-chain.pem | Adds valid cert chain fixture for TDX-related verification tests |
| pkg/crypto/testdata/tdx-cert-chain-revoked.pem | Adds revoked-chain fixture to test revocation handling |
| pkg/crypto/secp256_test.go | Adds Wycheproof vectors + cert-chain based verification tests/bench |
| pkg/crypto/secp256.go | Adds SecP256 (P-256 ECDSA) verification helper |
| pkg/crypto/groth16.go | Improves curve-switch error handling for Groth16 verification |
| pkg/crypto/crypto_test.go | Adds Digest.IsZero unit test |
| pkg/crypto/crypto.go | Adds Digest.IsZero helper |
| pkg/crypto/certificates_test.go | Adds tests/benchmarks for cert + CRL parsing and validation |
| pkg/crypto/certificates.go | Adds X.509 cert/CRL parsing, validation, and key extraction helpers |
| pkg/crypto/bls/pop_test.go | Adds PoP tests (round-trip + Scala compatibility) |
| pkg/crypto/bls/pop.go | Adds PoP message building + prove/verify helpers |
| pkg/crypto/bls/bls_test.go | Adds extensive BLS sign/verify/aggregate and Scala-compat tests |
| pkg/crypto/bls/bls.go | Adds CIRCL-backed BLS primitives + keygen options |
| pkg/consensus/validator_moq_test.go | Updates consensus mock to new height types + MGB lookup |
| pkg/consensus/blocks_validation_internal_test.go | Updates tests to fmt-based subtest naming |
| pkg/consensus/blocks_validation.go | Uses state-provided minimal generating balance; cleanup |
| pkg/client/transactions_info_test.go | Updates subtest naming helper usage |
| pkg/client/transactions_info.go | Adds CommitToGeneration transaction info type mapping |
| pkg/client/transactions.go | Adds /transactions/sign client call for commitment tx creation |
| pkg/client/generators.go | Adds client wrapper for generator endpoints |
| pkg/client/debug.go | Adds StateHash/StateHashDebug V1/V2 autodetection |
| pkg/client/client.go | Exposes new Generators client on root Client |
| pkg/client/blocks.go | Adds finalized height/header client methods |
| pkg/api/routes.go | Adds finalized endpoints + generators route + auth-protected tx signing |
| pkg/api/peers_test.go | Updates app construction to provide blockchain settings |
| pkg/api/peers.go | Switches to new structured BadRequest API error |
| pkg/api/node_api_test.go | Adds /transactions/sign commit-to-generation test + settings wiring |
| pkg/api/node_api.go | Adds finalized + generators endpoints; adds tx signing handler |
| pkg/api/errors_test.go | Updates expectations for new structured BadRequest errors |
| pkg/api/errors/consts.go | Adds new error IDs and renames JSON/API key constants |
| pkg/api/errors/basics.go | Adds structured Unavailable/BadRequest/NotImplemented errors |
| pkg/api/errors/auth.go | Updates API key error constant name |
| pkg/api/errors.go | Removes deprecated BadRequestError and updates handler behavior |
| pkg/api/blocks_test.go | Updates app construction to provide blockchain settings |
| pkg/api/app_test.go | Updates app construction to provide blockchain settings |
| pkg/api/app.go | Threads GenerationPeriod through app settings and uses new API errors |
| itests/snapshot_internal_test.go | Updates CreateBlock call signature |
| itests/finality_internal_test.go | Adds isolated deterministic finality integration suite |
| itests/config/genesis_settings.go | Adds BLS key material to genesis test accounts |
| itests/config/blockchain_options.go | Adds WithGenerationPeriod option and docs |
| itests/clients/universal_client.go | Adds wait helpers for height/tx in itests |
| itests/clients/node_client.go | Updates StateHash handling to new interface types |
| itests/clients/http_client.go | Adds finalized/generators/sign-commit HTTP helpers; testing.TB signatures |
| go.mod | Bumps Go version and adds circl dependency; updates x/exp |
| cmd/wallet/main.go | Switches wallet output to Fprintf(os.Stdout, ...) |
| cmd/statehash/statehash.go | Updates StateHashDebug handling to V1/V2 interface + finality fields |
| cmd/statecmp/statecmp.go | Updates statehash comparison and concurrency helper usage |
| cmd/rollback/main.go | Updates rollback call signature |
| cmd/node/node.go | Threads generation period into node run; adds endorsement pool |
| README.md | Updates minimum Go version statement |
| .semgrepignore | Ignores generated .pb.go files |
| .golangci.yml | Enables exhaustive switch checking |
| .gitmodules | Pins protobuf schemas submodule to deterministic-finality branch |
| .github/workflows/security.yml | Updates Go version + gosec exclude-generated |
| .github/workflows/run_itests.yml | Updates CI Go version |
| .github/workflows/publish-to-ghcr.yml | Updates CI Go version |
| .github/workflows/go.yml | Updates CI Go version and modernize invocation |
| .github/workflows/deploy_node.yml | Updates CI Go version |
| .github/workflows/codeql-analysis.yml | Updates CI Go version |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
crypto/ecdsa does not provide ParseUncompressedPublicKey in standard Go versions, which will fail to compile. Consider parsing the uncompressed point via elliptic.Unmarshal(curve, pkb) and constructing an ecdsa.PublicKey manually (and validating the point is on-curve), or switching to a supported API in your targeted Go version.
| x, y := elliptic.Unmarshal(curve, pkb) | |
| if x == nil || y == nil { | |
| return nil, errors.New("invalid public key: point not on curve or malformed") | |
| } | |
| return &ecdsa.PublicKey{Curve: curve, X: x, Y: y}, nil |
There was a problem hiding this comment.
stateInfoProvider.NewestMinimalGeneratingBalanceAtHeight takes height as proto.Height, but validateGeneratingBalance currently accepts height as uint64 and passes it directly. This is a compile-time type mismatch. Change validateGeneratingBalance’s height parameter type to proto.Height (preferred, for consistency with other state calls) or convert height explicitly before calling NewestMinimalGeneratingBalanceAtHeight.
| func (cv *Validator) validateGeneratingBalance(header *proto.BlockHeader, balance uint64, height proto.Height) error { |
There was a problem hiding this comment.
stateInfoProviderMock.NewestIsActiveAtHeightFunc was updated to take height as proto.Height, but this test still provides a function with height uint64, which will not compile. Update the callback signature to use proto.Height (and adjust any assertions accordingly).
There was a problem hiding this comment.
The JSON tag for BaseTarget is misspelled as baseTart. This will prevent BaseTarget from being unmarshaled and can cause V1/V2 detection to behave incorrectly (e.g., incorrectly classifying V2 as V1). Rename the tag to the correct field name used by the API response (likely baseTarget).
| BaseTarget uint64 `json:"baseTarget"` |
There was a problem hiding this comment.
Logging full transaction JSON in a client library can leak potentially sensitive information into application logs and can be very noisy in production. Consider removing this log, or gate it behind an explicit client option / injected logger with a disabled-by-default debug mode, and avoid logging the full payload (log tx type/id instead).
| slog.Debug("Broadcasting transaction") |
There was a problem hiding this comment.
This case sets out = nil for InvokeExpressionTransaction, but the function immediately treats nil as an error ('unknown transaction type'). If InvokeExpressionTransaction should be unsupported, return a dedicated 'unsupported/not implemented' error; if it should be ignored, adjust the API contract so callers can distinguish 'intentionally unsupported' from 'unknown'. As written, the comment 'Do nothing' is inconsistent with the behavior.
| // Known but currently unsupported transaction type. | |
| return nil, errors.Errorf("unsupported transaction type %d version %d", t.Type, t.Version) |
There was a problem hiding this comment.
On invalid height, this returns a generic wrapped error, which will likely be handled as an internal error (500). For a REST handler, invalid path params should return a structured 400 (e.g., apiErrs.NewBadRequestError(...)) for consistent client behavior.
| return apiErrs.NewBadRequestError(fmt.Errorf("invalid height: %w", err)) |
There was a problem hiding this comment.
Both error wraps use 'failed to get snapshot state hash…' even though the operations are 'IsActiveAtHeight' and 'HeaderByHeight'. This makes debugging harder. Update the wrap messages to reflect the actual failing call (e.g., 'failed to determine finality activation…' and 'failed to get block header…').
| return nil, errors.Wrapf(err, "failed to determine finality activation at height %d", height) | |
| } | |
| bh, bhErr := a.state.HeaderByHeight(height) | |
| if bhErr != nil { | |
| return nil, errors.Wrapf(bhErr, "failed to get block header at height %d", height) |
There was a problem hiding this comment.
sync.WaitGroup does not provide a Go method in standard Go versions, so this likely won’t compile unless you’ve introduced a custom type or are targeting a toolchain with this non-standard API. If the intent is to run goroutines with automatic Add/Done wiring, use errgroup.Group (recommended for propagating errors) or the classic wg.Add(1); go func(){ defer wg.Done(); ... }() pattern.
There was a problem hiding this comment.
The apiError case appears before the more specific UnavailableError case. If UnavailableError implements the ApiError interface (likely, since it embeds genericError), the apiError branch will handle it and the unavailableError branch becomes dead code. Consider removing the dedicated UnavailableError branch or moving it above the generic apiError match to keep the switch order meaningful.
No description provided.