Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions cmd/rpc/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@ func (s *Server) TransactionStake(w http.ResponseWriter, r *http.Request, _ http
if err != nil {
return nil, err
}
// Convert the public key from string to a crypto.PublicKey
pk, err := crypto.NewPublicKeyFromString(ptr.PubKey)
// Convert and validate the public key from string to a crypto.PublicKey
pk, err := stakePublicKeyFromRequest(ptr)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -584,8 +584,8 @@ func (s *Server) txHandler(w http.ResponseWriter, r *http.Request, callback func
write(w, err, http.StatusBadRequest)
return
}
// Set the public key in transaction request for reference.
ptr.PubKey = privateKey.PublicKey().String()
// Set the public key in transaction request for reference when one was not supplied.
setRequestPublicKey(ptr, privateKey)

// Call the provided callback function with the private key and transaction request.
p, err := callback(privateKey, ptr)
Expand All @@ -611,6 +611,23 @@ func (s *Server) txHandler(w http.ResponseWriter, r *http.Request, callback func
}
}

func stakePublicKeyFromRequest(ptr *txRequest) (crypto.PublicKeyI, error) {
pk, err := crypto.NewPublicKeyFromString(ptr.PubKey)
if err != nil {
return nil, err
}
if !bytes.Equal(pk.Address().Bytes(), ptr.Address) {
return nil, fmt.Errorf("stake public key address must match validator address")
}
return pk, nil
}

func setRequestPublicKey(ptr *txRequest, privateKey crypto.PrivateKeyI) {
if ptr.PubKey == "" {
ptr.PubKey = privateKey.PublicKey().String()
}
}

// AddVote adds a vote to a proposal
func (s *Server) AddVote(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
// Initialize a map to hold government proposals.
Expand Down
63 changes: 63 additions & 0 deletions cmd/rpc/admin_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package rpc

import (
"testing"

"github.com/canopy-network/canopy/lib/crypto"
"github.com/stretchr/testify/require"
)

func TestSetRequestPublicKeyPreservesExplicitPubKey(t *testing.T) {
operatorKey, err := crypto.NewBLS12381PrivateKey()
require.NoError(t, err)
signerKey, err := crypto.NewBLS12381PrivateKey()
require.NoError(t, err)

ptr := &txRequest{PubKey: operatorKey.PublicKey().String()}

setRequestPublicKey(ptr, signerKey)

require.Equal(t, operatorKey.PublicKey().String(), ptr.PubKey)
}

func TestSetRequestPublicKeyFallsBackToSignerPubKey(t *testing.T) {
signerKey, err := crypto.NewBLS12381PrivateKey()
require.NoError(t, err)

ptr := new(txRequest)

setRequestPublicKey(ptr, signerKey)

require.Equal(t, signerKey.PublicKey().String(), ptr.PubKey)
}

func TestStakePublicKeyFromRequestRequiresValidatorAddress(t *testing.T) {
operatorKey, err := crypto.NewBLS12381PrivateKey()
require.NoError(t, err)
signerKey, err := crypto.NewBLS12381PrivateKey()
require.NoError(t, err)

ptr := &txRequest{
PubKey: signerKey.PublicKey().String(),
addressRequest: addressRequest{Address: operatorKey.PublicKey().Address().Bytes()},
}

_, err = stakePublicKeyFromRequest(ptr)

require.ErrorContains(t, err, "stake public key address must match validator address")
}

func TestStakePublicKeyFromRequestAcceptsValidatorPubKey(t *testing.T) {
operatorKey, err := crypto.NewBLS12381PrivateKey()
require.NoError(t, err)

ptr := &txRequest{
PubKey: operatorKey.PublicKey().String(),
addressRequest: addressRequest{Address: operatorKey.PublicKey().Address().Bytes()},
}

got, err := stakePublicKeyFromRequest(ptr)

require.NoError(t, err)
require.True(t, operatorKey.PublicKey().Equals(got))
}