Skip to content

Commit

Permalink
resolved comments
Browse files Browse the repository at this point in the history
  • Loading branch information
calmbeing committed Apr 26, 2022
1 parent 838d08d commit 5401d4d
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 101 deletions.
22 changes: 22 additions & 0 deletions core/types/vote.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ package types
import (
"sync/atomic"

"github.com/prysmaticlabs/prysm/crypto/bls"

"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
)

const (
Expand Down Expand Up @@ -61,3 +64,22 @@ func (v *VoteEnvelope) calcVoteHash() common.Hash {
}

func (b BLSPublicKey) Bytes() []byte { return b[:] }

// VerifyVoteWithBLS using BLS.
func VerifyVoteWithBLS(vote *VoteEnvelope) error {
blsPubKey, err := bls.PublicKeyFromBytes(vote.VoteAddress[:])
if err != nil {
return errors.Wrap(err, "convert public key from bytes to bls failed")
}

sig, err := bls.SignatureFromBytes(vote.Signature[:])
if err != nil {
return errors.Wrap(err, "invalid signature")
}

voteDataHash := vote.Data.Hash()
if !sig.Verify(blsPubKey, voteDataHash[:]) {
return errors.New("verify bls signature failed.")
}
return nil
}
66 changes: 11 additions & 55 deletions core/vote/vote_manager.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
package vote

import (
"context"
"fmt"
"io/ioutil"

"github.com/prysmaticlabs/prysm/validator/accounts/iface"
"github.com/prysmaticlabs/prysm/validator/accounts/wallet"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
Expand All @@ -20,7 +15,7 @@ import (
)

type (
getHighestJustifiedHeader func(chain consensus.ChainHeaderReader, header *types.Header) *types.Header
getHighestJustifiedHeaderFunc func(chain consensus.ChainHeaderReader, header *types.Header) *types.Header
)

// VoteManager will handle the vote produced by self.
Expand All @@ -39,10 +34,10 @@ type VoteManager struct {

engine consensus.PoSA

get getHighestJustifiedHeader
getHighestJustifiedHeader getHighestJustifiedHeaderFunc
}

func NewVoteManager(mux *event.TypeMux, chainconfig *params.ChainConfig, chain *core.BlockChain, pool *VotePool, journalPath, blsPasswordPath, blsWalletPath string, engine consensus.PoSA, get getHighestJustifiedHeader) (*VoteManager, error) {
func NewVoteManager(mux *event.TypeMux, chainconfig *params.ChainConfig, chain *core.BlockChain, pool *VotePool, journalPath, blsPasswordPath, blsWalletPath string, engine consensus.PoSA, getHighestJustifiedHeader getHighestJustifiedHeaderFunc) (*VoteManager, error) {
voteManager := &VoteManager{
mux: mux,

Expand All @@ -53,45 +48,11 @@ func NewVoteManager(mux *event.TypeMux, chainconfig *params.ChainConfig, chain *
pool: pool,
engine: engine,

get: get,
}

dirExists, err := wallet.Exists(blsWalletPath)
if err != nil {
log.Error("Check BLS wallet exists error: %v.", err)
return nil, err
}
if !dirExists {
log.Error("BLS wallet did not exists.")
return nil, fmt.Errorf("BLS wallet did not exists.")
}

walletPassword, err := ioutil.ReadFile(blsPasswordPath)
if err != nil {
log.Error("Read BLS wallet password error: %v.", err)
return nil, err
}
log.Info("Read BLS wallet password successfully")

w, err := wallet.OpenWallet(context.Background(), &wallet.Config{
WalletDir: blsWalletPath,
WalletPassword: string(walletPassword),
})
if err != nil {
log.Error("Open BLS wallet failed: %v.", err)
return nil, err
}
log.Info("Open BLS wallet successfully")

km, err := w.InitializeKeymanager(context.Background(), iface.InitKeymanagerConfig{ListenForChanges: false})
if err != nil {
log.Error("Initialize key manager failed: %v.", err)
return nil, err
getHighestJustifiedHeader: getHighestJustifiedHeader,
}
log.Info("Initialized keymanager successfully")

// Create voteSigner
voteSigner, err := NewVoteSigner(&km)
// Create voteSigner.
voteSigner, err := NewVoteSigner(blsPasswordPath, blsWalletPath)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -194,7 +155,7 @@ func (voteManager *VoteManager) loop() {
// A validator must not vote within the span of its other votes . (Rule 2)
// Validators always vote for their canonical chain’s latest block. (Rule 3)
func (voteManager *VoteManager) UnderRules(header *types.Header) (bool, uint64, common.Hash) {
justifiedHeader := voteManager.get(voteManager.chain, header)
justifiedHeader := voteManager.getHighestJustifiedHeader(voteManager.chain, header)
if justifiedHeader == nil {
log.Error("highestJustifiedHeader is nil")
return false, 0, common.Hash{}
Expand All @@ -219,21 +180,16 @@ func (voteManager *VoteManager) UnderRules(header *types.Header) (bool, uint64,
return false, 0, common.Hash{}
}

journalLatestVote, err := journal.ReadVote(lastIndex)
if err != nil {
return false, 0, common.Hash{}
}
if journalLatestVote == nil {
// Indicate there's no vote before in local node, so it must be under rules.
return true, sourceNumber, sourceHash
}

for index := lastIndex; index >= firstIndex; index-- {
vote, err := journal.ReadVote(index)
if err != nil {
return false, 0, common.Hash{}
}
if vote == nil {
// Indicate there's no vote in local journal, so it must be under rules.
if lastIndex == 0 && firstIndex == 0 {
return true, sourceNumber, sourceHash
}
log.Error("vote is nil")
return false, 0, common.Hash{}
}
Expand Down
49 changes: 26 additions & 23 deletions core/vote/vote_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,17 +139,6 @@ func (pool *VotePool) putIntoVotePool(vote *types.VoteEnvelope) bool {
votesPq = pool.futureVotesPq
isFutureVote = true
} else {
// Verify if the vote comes from valid validators based on voteAddress (BLSPublicKey).
if posa, ok := pool.engine.(consensus.PoSA); ok {
if !posa.VerifyVote(pool.chain, vote) {
return false
}
}
// Verify bls signature.
if err := VerifyVoteWithBLS(vote); err != nil {
log.Error("Failed to verify voteMessage", "err", err)
return false
}
votes = pool.curVotes
votesPq = pool.curVotesPq
}
Expand All @@ -159,14 +148,20 @@ func (pool *VotePool) putIntoVotePool(vote *types.VoteEnvelope) bool {
return false
}

pool.putVote(votes, votesPq, vote, voteData, voteHash, isFutureVote)

if !isFutureVote {
// Verify if the vote comes from valid validators based on voteAddress (BLSPublicKey), only verify curVotes here, will verify futureVotes in transfer process.
if posa, ok := pool.engine.(consensus.PoSA); ok {
if !posa.VerifyVote(pool.chain, vote) {
return false
}
}
// Send vote for handler usage of broadcasting to peers.
voteEv := core.NewVoteEvent{Vote: vote}
pool.votesFeed.Send(voteEv)
}

pool.putVote(votes, votesPq, vote, voteData, voteHash, isFutureVote)

return true
}

Expand Down Expand Up @@ -259,13 +254,11 @@ func (pool *VotePool) transfer(blockHash common.Hash) {
continue
}
}
// Verify the vote from futureVotes.
if err := VerifyVoteWithBLS(vote); err == nil {
// In the process of transfer, send valid vote to votes channel for handler usage
voteEv := core.NewVoteEvent{Vote: vote}
pool.votesFeed.Send(voteEv)
validVotes = append(validVotes, vote)
}

// In the process of transfer, send valid vote to votes channel for handler usage
voteEv := core.NewVoteEvent{Vote: vote}
pool.votesFeed.Send(voteEv)
validVotes = append(validVotes, vote)
}

voteData := heap.Pop(futurePq)
Expand Down Expand Up @@ -349,15 +342,25 @@ func (pool *VotePool) basicVerify(vote *types.VoteEnvelope, headNumber uint64, m
log.Warn("BlockNumber of vote is outside the range of header-256~header+13")
return false
}
// To prevent DOS attacks, make sure no more than 50 votes for the same blockHash if it's futureVotes
// No more than 21 votes per blockHash if not futureVotes and no more than 50 votes per blockHash if futureVotes

// To prevent DOS attacks, make sure no more than 21 votes per blockHash if not futureVotes
// and no more than 50 votes per blockHash if futureVotes.
maxVoteAmountPerBlock := maxCurVoteAmountPerBlock
if isFutureVote {
maxVoteAmountPerBlock = maxFutureVoteAmountPerBlock
}
if voteBox, ok := m[targetHash]; ok {
return len(voteBox.voteMessages) <= maxVoteAmountPerBlock
if len(voteBox.voteMessages) > maxVoteAmountPerBlock {
return false
}
}

// Verify bls signature.
if err := types.VerifyVoteWithBLS(vote); err != nil {
log.Error("Failed to verify voteMessage", "err", err)
return false
}

return true
}

Expand Down
2 changes: 1 addition & 1 deletion core/vote/vote_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ func testVotePool(t *testing.T, inValidRules bool) {
file.Close()
os.Remove(journal)

var ruleFunc getHighestJustifiedHeader
var ruleFunc getHighestJustifiedHeaderFunc
if inValidRules {
ruleFunc = getHighestJustifiedHeaderForValid
} else {
Expand Down
64 changes: 42 additions & 22 deletions core/vote/vote_signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@ package vote
import (
"context"
"fmt"
"io/ioutil"
"time"

"github.com/pkg/errors"

"github.com/prysmaticlabs/prysm/crypto/bls"
validatorpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/validator-client"
"github.com/prysmaticlabs/prysm/validator/accounts/iface"
"github.com/prysmaticlabs/prysm/validator/accounts/wallet"
"github.com/prysmaticlabs/prysm/validator/keymanager"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
)

Expand All @@ -25,16 +29,51 @@ type VoteSigner struct {
pubKey [48]byte
}

func NewVoteSigner(km *keymanager.IKeymanager) (*VoteSigner, error) {
func NewVoteSigner(blsPasswordPath, blsWalletPath string) (*VoteSigner, error) {
dirExists, err := wallet.Exists(blsWalletPath)
if err != nil {
log.Error("Check BLS wallet exists error: %v.", err)
return nil, err
}
if !dirExists {
log.Error("BLS wallet did not exists.")
return nil, fmt.Errorf("BLS wallet did not exists.")
}

walletPassword, err := ioutil.ReadFile(blsPasswordPath)
if err != nil {
log.Error("Read BLS wallet password error: %v.", err)
return nil, err
}
log.Info("Read BLS wallet password successfully")

w, err := wallet.OpenWallet(context.Background(), &wallet.Config{
WalletDir: blsWalletPath,
WalletPassword: string(walletPassword),
})
if err != nil {
log.Error("Open BLS wallet failed: %v.", err)
return nil, err
}
log.Info("Open BLS wallet successfully")

km, err := w.InitializeKeymanager(context.Background(), iface.InitKeymanagerConfig{ListenForChanges: false})
if err != nil {
log.Error("Initialize key manager failed: %v.", err)
return nil, err
}
log.Info("Initialized keymanager successfully")

ctx, cancel := context.WithTimeout(context.Background(), voteSignerTimeout)
defer cancel()

pubKeys, err := (*km).FetchValidatingPublicKeys(ctx)
pubKeys, err := km.FetchValidatingPublicKeys(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not fetch validating public keys")
}

return &VoteSigner{
km: km,
km: &km,
pubKey: pubKeys[0],
}, nil
}
Expand Down Expand Up @@ -65,25 +104,6 @@ func (signer *VoteSigner) SignVote(vote *types.VoteEnvelope) error {
return nil
}

// VerifyVoteWithBLS using BLS.
func VerifyVoteWithBLS(vote *types.VoteEnvelope) error {
blsPubKey, err := bls.PublicKeyFromBytes(vote.VoteAddress[:])
if err != nil {
return errors.Wrap(err, "convert public key from bytes to bls failed")
}

sig, err := bls.SignatureFromBytes(vote.Signature[:])
if err != nil {
return errors.Wrap(err, "invalid signature")
}

voteDataHash := vote.Data.Hash()
if !sig.Verify(blsPubKey, voteDataHash[:]) {
return errors.New("verify bls signature failed.")
}
return nil
}

// Metrics to indicate if there's any failed signing.
func votesSigningErrorMetric(blockNumber uint64, blockHash common.Hash) metrics.Gauge {
return metrics.GetOrRegisterGauge(fmt.Sprintf("voteSigning/blockNumber/%d/blockHash/%s", blockNumber, blockHash), nil)
Expand Down

0 comments on commit 5401d4d

Please sign in to comment.