-
Notifications
You must be signed in to change notification settings - Fork 69
Node api finality #1897
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: add-network-messages
Are you sure you want to change the base?
Node api finality #1897
Conversation
pkg/wallet/stub.go
Outdated
| func (s Stub) SignTransactionWith(pk crypto.PublicKey, tx proto.Transaction) error { | ||
| panic("Stub.SignTransactionWith: Unsupported operation") | ||
| func (s Stub) SignTransactionWith(_ crypto.PublicKey, _ proto.Transaction) error { | ||
| panic("Stub.SignTransactionWith: Unsopported operation") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the word “unsOpported” exist?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
pkg/wallet/embedded_wallet.go
Outdated
| return crypto.PublicKey{}, ErrPublicKeyNotFound | ||
| } | ||
|
|
||
| func (a *EmbeddedWalletImpl) BlsPairByWavesPK(publicKey crypto.PublicKey) (bls.SecretKey, bls.PublicKey, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Bls" should be "BLS".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
pkg/state/commitments.go
Outdated
|
|
||
| // FindEndorserPKsByIndexes returns BLS endorser public keys using | ||
| // commitment indexes stored in FinalizationVoting.EndorserIndexes. | ||
| func (c *commitments) FindEndorserPKsByIndexes( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why "PKs" and "indexes", not "PK" and "index", the function returns only one public key and accepts only one index.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
pkg/state/finalization.go
Outdated
| "github.com/wavesplatform/gowaves/pkg/proto" | ||
| ) | ||
|
|
||
| const finalizationKey = "finalization" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All keys have to be introduced in
Line 139 in 8b0ac77
| commitmentKeyPrefix |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
pkg/state/finalization.go
Outdated
| var ErrNoFinalizationHistory = errors.New("no finalization in history") | ||
|
|
||
| type finalizationItem struct { | ||
| Block proto.BlockHeader `cbor:"0,keyasint,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to store block header second time here, can be retrieved by height or blockID.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
| func (fr *finalizationRecord) unmarshalBinary(data []byte) error { return cbor.Unmarshal(data, fr) } | ||
|
|
||
| type finalizations struct { | ||
| hs *historyStorage |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we discussed the finalization storage should not be a history storage. In case of using history the rollback will happen automatically, but the idea of finalization records that they are irreversible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The finalization now contains only one item, I kept the history storage. Moved it to the other PR
pkg/state/appender.go
Outdated
| return false, fmt.Errorf("failed to build endorsement message: %w", err) | ||
| } | ||
|
|
||
| // 2. Восстанавливаем endorser PK по индексам |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh no! Please use English only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
pkg/state/appender.go
Outdated
| return nil | ||
| } | ||
|
|
||
| func (a *txAppender) isLastBlockFinalized( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Strange naming, is it better to name the function "updateFinalization" or "calculateFinalization"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
pkg/state/appender.go
Outdated
| if err != nil { | ||
| return false, err | ||
| } | ||
| msg, err := proto.EndorsementMessage( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why construct an endorsement message here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see, it's for block header validation. I'd rather move this function to proto package, somewhere near block declaration or even made it a part of Block type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which file are you suggesting to move it to?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because this function EndorsementMessage is already in proto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corresponding `pkg/client' parts have to be implemented.
|
Moved storage to add-network-messages |
pkg/api/app.go
Outdated
| return nil, err | ||
| } | ||
|
|
||
| settings.GenerationPeriod = cfg.GenerationPeriod |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Current argument name collides with the package name. Suggest to rename variable.
| activationHeight, err := a.state.ActivationHeight(int16(settings.DeterministicFinality)) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to get DeterministicFinality activation height: %w", err) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if activation height is unknown at the moment? I think the endpoint returns 500 error in such case.
pkg/api/node_api.go
Outdated
| periodStart, err := state.CurrentGenerationPeriodStart(activationHeight, height, | ||
| a.app.settings.GenerationPeriod) | ||
| if err != nil { | ||
| return err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add errors context here and below (use fmt.Errorf I mean).
pkg/api/node_api.go
Outdated
| type GeneratorInfo struct { | ||
| Address string `json:"address"` | ||
| Balance uint64 `json:"balance"` | ||
| TransactionID string `json:"transactionID"` | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This struct must be package private.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's now used in 2 different packages
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but it's an implementation details of our API. It should not be exported to the client packages.
pkg/client/generators.go
Outdated
| if err != nil { | ||
| return nil, nil, err | ||
| } | ||
| var out []api.GeneratorInfo |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better to create new struct for response without using api package.
pkg/client/generators.go
Outdated
| "fmt" | ||
| "net/http" | ||
|
|
||
| "github.com/wavesplatform/gowaves/pkg/api" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not import api package here. api package is our node implementation details, while client is a library.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see a problem in a library using node API structures
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No changes are necessary
pkg/wallet/stub.go
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file can be completely removed. At least Deprecated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 20 out of 20 changed files in this pull request and generated 11 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| } | ||
|
|
||
| type SignCommitRequest struct { | ||
| Sender string `json:"sender"` |
Copilot
AI
Dec 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The SignCommitRequest struct is defined in both pkg/client/transactions.go and pkg/api/node_api.go with different fields. The client version lacks the ChainID field that is present in the API version. This inconsistency could lead to issues when the client sends requests to the API endpoint, as the client won't be able to specify ChainID even if needed. Consider consolidating these struct definitions or ensuring the client struct includes all fields that the API can accept.
| Sender string `json:"sender"` | |
| Sender string `json:"sender"` | |
| ChainID *byte `json:"chainId,omitempty"` |
| ChainID *byte `json:"chainId,omitempty"` | ||
| } |
Copilot
AI
Dec 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ChainID field in SignCommitRequest is accepted but never used in the TransactionsSignCommit function. This field should either be removed from the struct if it's not needed, or the value should be used appropriately when creating or signing the transaction.
| secretKeyBls, genErr := bls.GenerateSecretKey(s) | ||
| if genErr != nil { | ||
| return bls.SecretKey{}, bls.PublicKey{}, genErr | ||
| } | ||
| publicKeyBls, retrieveErr := secretKeyBls.PublicKey() | ||
| if retrieveErr != nil { | ||
| return bls.SecretKey{}, bls.PublicKey{}, retrieveErr |
Copilot
AI
Dec 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable naming is inconsistent within this function. The function uses 'publicKeyRetrieved' for the generated public key but then uses different error variable names (genErr, retrieveErr) which breaks the naming pattern. Consider using more consistent naming like 'err' for all error variables or using a consistent pattern throughout.
| secretKeyBls, genErr := bls.GenerateSecretKey(s) | |
| if genErr != nil { | |
| return bls.SecretKey{}, bls.PublicKey{}, genErr | |
| } | |
| publicKeyBls, retrieveErr := secretKeyBls.PublicKey() | |
| if retrieveErr != nil { | |
| return bls.SecretKey{}, bls.PublicKey{}, retrieveErr | |
| secretKeyBls, err := bls.GenerateSecretKey(s) | |
| if err != nil { | |
| return bls.SecretKey{}, bls.PublicKey{}, err | |
| } | |
| publicKeyBls, err := secretKeyBls.PublicKey() | |
| if err != nil { | |
| return bls.SecretKey{}, bls.PublicKey{}, err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bad AI, your suggestion will shadow errors, which is a worse pattern
pkg/api/node_api.go
Outdated
| var generatorsInfo []GeneratorInfo | ||
|
|
||
| generatorAddresses, err := a.state.CommittedGenerators(periodStart) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| for _, generatorAddress := range generatorAddresses { | ||
| endorserRecipient := proto.NewRecipientFromAddress(generatorAddress) | ||
| balance, pullErr := a.state.GeneratingBalance(endorserRecipient, height) | ||
| if pullErr != nil { | ||
| return pullErr | ||
| } | ||
| generatorsInfo = append(generatorsInfo, GeneratorInfo{ | ||
| Address: generatorAddress.String(), | ||
| Balance: balance, | ||
| TransactionID: "", // TODO should be somehow found. | ||
| }) | ||
| } |
Copilot
AI
Dec 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The generatorsInfo slice is appended to without pre-allocation. Since the number of generators is known from len(generatorAddresses), consider pre-allocating the slice with make([]GeneratorInfo, 0, len(generatorAddresses)) to avoid potential reallocation overhead during iteration.
| func (a *EmbeddedWalletImpl) FindPublicKeyByAddress(address proto.WavesAddress, | ||
| scheme proto.Scheme) (crypto.PublicKey, error) { | ||
| seeds := a.seeder.AccountSeeds() | ||
| for _, s := range seeds { | ||
| _, public, err := crypto.GenerateKeyPair(s) | ||
| if err != nil { | ||
| return crypto.PublicKey{}, err | ||
| } | ||
| retrievedAddress, err := proto.NewAddressFromPublicKey(scheme, public) | ||
| if err != nil { | ||
| return crypto.PublicKey{}, err | ||
| } | ||
| if retrievedAddress == address { | ||
| return public, nil | ||
| } | ||
| } | ||
| return crypto.PublicKey{}, ErrPublicKeyNotFound | ||
| } |
Copilot
AI
Dec 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new FindPublicKeyByAddress method lacks test coverage. Since the existing SignTransactionWith method has tests in embedded_wallet_test.go, consider adding test cases for this new method to ensure it correctly finds public keys by address and handles error cases like when the address is not found.
| func (a *Blocks) HeightFinalized(ctx context.Context) (uint64, *Response, error) { | ||
| url, err := joinUrl(a.options.BaseUrl, "/blocks/height/finalized") | ||
| if err != nil { | ||
| return 0, nil, err | ||
| } | ||
|
|
||
| req, err := http.NewRequestWithContext(ctx, http.MethodGet, url.String(), nil) | ||
| if err != nil { | ||
| return 0, nil, err | ||
| } | ||
|
|
||
| var out struct { | ||
| Height uint64 `json:"height"` | ||
| } | ||
|
|
||
| resp, err := doHTTP(ctx, a.options, req, &out) | ||
| if err != nil { | ||
| return 0, resp, err | ||
| } | ||
|
|
||
| return out.Height, resp, nil | ||
| } | ||
|
|
||
| func (a *Blocks) BlockFinalized(ctx context.Context) (*proto.BlockHeader, *Response, error) { | ||
| url, err := joinUrl(a.options.BaseUrl, "/blocks/headers/finalized") | ||
| if err != nil { | ||
| return nil, nil, err | ||
| } | ||
|
|
||
| req, err := http.NewRequestWithContext(ctx, http.MethodGet, url.String(), nil) | ||
| if err != nil { | ||
| return nil, nil, err | ||
| } | ||
| var out proto.BlockHeader | ||
| resp, err := doHTTP(ctx, a.options, req, &out) | ||
| if err != nil { | ||
| return nil, resp, err | ||
| } | ||
| return &out, resp, nil | ||
| } |
Copilot
AI
Dec 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new HeightFinalized and BlockFinalized methods lack test coverage. Since other methods in blocks_test.go have comprehensive tests, consider adding test cases for these new finalized block endpoints to ensure they correctly retrieve finalized data and handle error cases.
| package client | ||
|
|
||
| import ( | ||
| "context" | ||
| "fmt" | ||
| "net/http" | ||
|
|
||
| "github.com/wavesplatform/gowaves/pkg/api" | ||
| ) | ||
|
|
||
| // Generators is a client wrapper for generator-related API endpoints. | ||
| type Generators struct { | ||
| options Options | ||
| } | ||
|
|
||
| func NewGenerators(options Options) *Generators { | ||
| return &Generators{ | ||
| options: options, | ||
| } | ||
| } | ||
|
|
||
| // GeneratorsAtResponse is the expected structure returned by /generators/at/{height}. | ||
| type GeneratorsAtResponse struct { | ||
| Height uint64 `json:"height"` | ||
| Generators []string `json:"generators"` | ||
| } | ||
|
|
||
| // CommitmentGeneratorsAt returns the list of committed generators for the given height. | ||
| func (a *Generators) CommitmentGeneratorsAt(ctx context.Context, | ||
| height uint64) ([]api.GeneratorInfo, *Response, error) { | ||
| url, err := joinUrl(a.options.BaseUrl, fmt.Sprintf("/generators/at/%d", height)) | ||
| if err != nil { | ||
| return nil, nil, err | ||
| } | ||
| req, err := http.NewRequestWithContext(ctx, http.MethodGet, url.String(), nil) | ||
| if err != nil { | ||
| return nil, nil, err | ||
| } | ||
| var out []api.GeneratorInfo | ||
| resp, err := doHTTP(ctx, a.options, req, &out) | ||
| if err != nil { | ||
| return nil, resp, err | ||
| } | ||
|
|
||
| return out, resp, nil | ||
| } |
Copilot
AI
Dec 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new Generators client wrapper lacks test coverage. Since other client files in this directory have corresponding test files, consider creating generators_test.go with tests for the CommitmentGeneratorsAt method.
| func (a *EmbeddedWalletImpl) BLSPairByWavesPK(publicKey crypto.PublicKey) (bls.SecretKey, bls.PublicKey, error) { | ||
| seeds := a.seeder.AccountSeeds() | ||
| for _, s := range seeds { | ||
| _, publicKeyRetrieved, err := crypto.GenerateKeyPair(s) | ||
| if err != nil { | ||
| return bls.SecretKey{}, bls.PublicKey{}, err | ||
| } | ||
| if publicKeyRetrieved == publicKey { | ||
| secretKeyBls, genErr := bls.GenerateSecretKey(s) | ||
| if genErr != nil { | ||
| return bls.SecretKey{}, bls.PublicKey{}, genErr | ||
| } | ||
| publicKeyBls, retrieveErr := secretKeyBls.PublicKey() | ||
| if retrieveErr != nil { | ||
| return bls.SecretKey{}, bls.PublicKey{}, retrieveErr | ||
| } | ||
| return secretKeyBls, publicKeyBls, nil | ||
| } | ||
| } | ||
| return bls.SecretKey{}, bls.PublicKey{}, ErrPublicKeyNotFound | ||
| } |
Copilot
AI
Dec 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new BLSPairByWavesPK method lacks test coverage. Since the existing SignTransactionWith method has tests in embedded_wallet_test.go, consider adding test cases for this new method to verify it correctly generates BLS key pairs from Waves public keys and handles error cases appropriately.
pkg/client/generators.go
Outdated
| // GeneratorsAtResponse is the expected structure returned by /generators/at/{height}. | ||
| type GeneratorsAtResponse struct { | ||
| Height uint64 `json:"height"` | ||
| Generators []string `json:"generators"` | ||
| } | ||
|
|
Copilot
AI
Dec 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The GeneratorsAtResponse struct is defined but never used. The CommitmentGeneratorsAt method returns []api.GeneratorInfo instead. Consider removing this unused struct or using it as the actual return type if that was the original intent.
| // GeneratorsAtResponse is the expected structure returned by /generators/at/{height}. | |
| type GeneratorsAtResponse struct { | |
| Height uint64 `json:"height"` | |
| Generators []string `json:"generators"` | |
| } |
pkg/api/node_api.go
Outdated
| generatorsInfo = append(generatorsInfo, GeneratorInfo{ | ||
| Address: generatorAddress.String(), | ||
| Balance: balance, | ||
| TransactionID: "", // TODO should be somehow found. |
Copilot
AI
Dec 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The TransactionID field is always set to an empty string with a TODO comment indicating it should be found somehow. This incomplete implementation means the API returns incomplete data to clients. Consider either implementing the lookup for TransactionID or documenting why it's not available and potentially making the field optional or removing it if it cannot be populated.
| TransactionID: "", // TODO should be somehow found. | |
| TransactionID: "", // TransactionID is currently not available and remains empty for backward compatibility. |
| authError *AuthError | ||
| unknownError *apiErrs.UnknownError | ||
| apiError apiErrs.ApiError | ||
| unavailableError *apiErrs.UnavailableError |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New error should implement ApiError interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They already do
pkg/api/errors/consts.go
Outdated
| // API Auth | ||
| const ( | ||
| ApiKeyNotValidErrorID ApiAuthErrorID = 2 | ||
| APIKeyNotValidErrorID ApiAuthErrorID = 4 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These constants IDs should not be changed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is that?
pkg/api/node_api.go
Outdated
| type GeneratorInfo struct { | ||
| Address string `json:"address"` | ||
| Balance uint64 `json:"balance"` | ||
| TransactionID string `json:"transactionID"` | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but it's an implementation details of our API. It should not be exported to the client packages.
pkg/api/routes.go
Outdated
|
|
||
| rAuth := r.With(checkAuthMiddleware) | ||
| rAuth.Post("/sign", wrapper(a.TransactionsSignCommit)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we need to discuss it with the team.
Agreed
No description provided.