Skip to content

Conversation

@esuwu
Copy link
Contributor

@esuwu esuwu commented Nov 11, 2025

No description provided.

@esuwu esuwu requested a review from alexeykiselev November 24, 2025 09:13
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")
Copy link
Collaborator

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

return crypto.PublicKey{}, ErrPublicKeyNotFound
}

func (a *EmbeddedWalletImpl) BlsPairByWavesPK(publicKey crypto.PublicKey) (bls.SecretKey, bls.PublicKey, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Bls" should be "BLS".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed


// FindEndorserPKsByIndexes returns BLS endorser public keys using
// commitment indexes stored in FinalizationVoting.EndorserIndexes.
func (c *commitments) FindEndorserPKsByIndexes(
Copy link
Collaborator

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

"github.com/wavesplatform/gowaves/pkg/proto"
)

const finalizationKey = "finalization"
Copy link
Collaborator

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

commitmentKeyPrefix

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

var ErrNoFinalizationHistory = errors.New("no finalization in history")

type finalizationItem struct {
Block proto.BlockHeader `cbor:"0,keyasint,omitempty"`
Copy link
Collaborator

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.

Copy link
Contributor Author

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
Copy link
Collaborator

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.

Copy link
Contributor Author

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

return false, fmt.Errorf("failed to build endorsement message: %w", err)
}

// 2. Восстанавливаем endorser PK по индексам
Copy link
Collaborator

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

return nil
}

func (a *txAppender) isLastBlockFinalized(
Copy link
Collaborator

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"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

if err != nil {
return false, err
}
msg, err := proto.EndorsementMessage(
Copy link
Collaborator

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?

Copy link
Collaborator

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.

Copy link
Contributor Author

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?

Copy link
Contributor Author

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

Copy link
Collaborator

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.

@esuwu
Copy link
Contributor Author

esuwu commented Dec 3, 2025

Moved storage to add-network-messages

pkg/api/app.go Outdated
return nil, err
}

settings.GenerationPeriod = cfg.GenerationPeriod
Copy link
Collaborator

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.

Comment on lines +934 to +937
activationHeight, err := a.state.ActivationHeight(int16(settings.DeterministicFinality))
if err != nil {
return fmt.Errorf("failed to get DeterministicFinality activation height: %w", err)
}
Copy link
Collaborator

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.

periodStart, err := state.CurrentGenerationPeriodStart(activationHeight, height,
a.app.settings.GenerationPeriod)
if err != nil {
return err
Copy link
Collaborator

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).

Comment on lines 921 to 925
type GeneratorInfo struct {
Address string `json:"address"`
Balance uint64 `json:"balance"`
TransactionID string `json:"transactionID"`
}
Copy link
Collaborator

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.

Copy link
Contributor Author

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

Copy link
Collaborator

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.

if err != nil {
return nil, nil, err
}
var out []api.GeneratorInfo
Copy link
Collaborator

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.

"fmt"
"net/http"

"github.com/wavesplatform/gowaves/pkg/api"
Copy link
Collaborator

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.

Copy link
Contributor Author

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

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No changes are necessary

Copy link
Collaborator

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.

Copy link
Contributor

Copilot AI left a 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.

@nickeskov nickeskov requested a review from Copilot December 17, 2025 22:59
Copy link
Contributor

Copilot AI left a 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"`
Copy link

Copilot AI Dec 17, 2025

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.

Suggested change
Sender string `json:"sender"`
Sender string `json:"sender"`
ChainID *byte `json:"chainId,omitempty"`

Copilot uses AI. Check for mistakes.
Comment on lines 973 to 974
ChainID *byte `json:"chainId,omitempty"`
}
Copy link

Copilot AI Dec 17, 2025

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.

Copilot uses AI. Check for mistakes.
Comment on lines +63 to +69
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
Copy link

Copilot AI Dec 17, 2025

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.

Suggested change
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

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

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

Comment on lines 932 to 949
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.
})
}
Copy link

Copilot AI Dec 17, 2025

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.

Copilot uses AI. Check for mistakes.
Comment on lines +36 to +53
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
}
Copy link

Copilot AI Dec 17, 2025

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.

Copilot uses AI. Check for mistakes.
Comment on lines +314 to +353
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
}
Copy link

Copilot AI Dec 17, 2025

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.

Copilot uses AI. Check for mistakes.
Comment on lines 1 to 46
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
}
Copy link

Copilot AI Dec 17, 2025

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.

Copilot uses AI. Check for mistakes.
Comment on lines +55 to +75
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
}
Copy link

Copilot AI Dec 17, 2025

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.

Copilot uses AI. Check for mistakes.
Comment on lines 22 to 27
// GeneratorsAtResponse is the expected structure returned by /generators/at/{height}.
type GeneratorsAtResponse struct {
Height uint64 `json:"height"`
Generators []string `json:"generators"`
}

Copy link

Copilot AI Dec 17, 2025

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.

Suggested change
// GeneratorsAtResponse is the expected structure returned by /generators/at/{height}.
type GeneratorsAtResponse struct {
Height uint64 `json:"height"`
Generators []string `json:"generators"`
}

Copilot uses AI. Check for mistakes.
generatorsInfo = append(generatorsInfo, GeneratorInfo{
Address: generatorAddress.String(),
Balance: balance,
TransactionID: "", // TODO should be somehow found.
Copy link

Copilot AI Dec 17, 2025

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.

Suggested change
TransactionID: "", // TODO should be somehow found.
TransactionID: "", // TransactionID is currently not available and remains empty for backward compatibility.

Copilot uses AI. Check for mistakes.
authError *AuthError
unknownError *apiErrs.UnknownError
apiError apiErrs.ApiError
unavailableError *apiErrs.UnavailableError
Copy link
Collaborator

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.

Copy link
Contributor Author

@esuwu esuwu Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They already do

// API Auth
const (
ApiKeyNotValidErrorID ApiAuthErrorID = 2
APIKeyNotValidErrorID ApiAuthErrorID = 4
Copy link
Collaborator

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is that?

Comment on lines 921 to 925
type GeneratorInfo struct {
Address string `json:"address"`
Balance uint64 `json:"balance"`
TransactionID string `json:"transactionID"`
}
Copy link
Collaborator

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.

Comment on lines 147 to 149

rAuth := r.With(checkAuthMiddleware)
rAuth.Post("/sign", wrapper(a.TransactionsSignCommit))
Copy link
Collaborator

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants