Skip to content
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

Multikey peer authentication sender integration #4394

Merged
merged 13 commits into from
Aug 31, 2022
Merged
2 changes: 1 addition & 1 deletion consensus/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ type BroadcastMessenger interface {
// P2PMessenger defines a subset of the p2p.Messenger interface
type P2PMessenger interface {
Broadcast(topic string, buff []byte)
BroadcastWithSk(topic string, buff []byte, pid core.PeerID, skBytes []byte)
BroadcastUsingPrivateKey(topic string, buff []byte, pid core.PeerID, skBytes []byte)
IsInterfaceNil() bool
}

Expand Down
12 changes: 6 additions & 6 deletions consensus/mock/messengerStub.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@ import "github.com/ElrondNetwork/elrond-go-core/core"

// MessengerStub -
type MessengerStub struct {
BroadcastWithSkCalled func(topic string, buff []byte, pid core.PeerID, skBytes []byte)
BroadcastCalled func(topic string, buff []byte)
BroadcastUsingPrivateKeyCalled func(topic string, buff []byte, pid core.PeerID, skBytes []byte)
BroadcastCalled func(topic string, buff []byte)
}

// Broadcast -
func (ms *MessengerStub) Broadcast(topic string, buff []byte) {
ms.BroadcastCalled(topic, buff)
}

// BroadcastWithSk -
func (ms *MessengerStub) BroadcastWithSk(topic string, buff []byte, pid core.PeerID, skBytes []byte) {
if ms.BroadcastWithSkCalled != nil {
ms.BroadcastWithSkCalled(topic, buff, pid, skBytes)
// BroadcastUsingPrivateKey -
func (ms *MessengerStub) BroadcastUsingPrivateKey(topic string, buff []byte, pid core.PeerID, skBytes []byte) {
if ms.BroadcastUsingPrivateKeyCalled != nil {
ms.BroadcastUsingPrivateKeyCalled(topic, buff, pid, skBytes)
}
}

Expand Down
3 changes: 3 additions & 0 deletions heartbeat/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,6 @@ var ErrNilEnableEpochsHandler = errors.New("nil enable epochs handler")

// ErrShouldSkipValidator signals that the validator should be skipped
var ErrShouldSkipValidator = errors.New("validator should be skipped")

// ErrNilKeysHolder signals that a nil keys holder has been provided
var ErrNilKeysHolder = errors.New("nil keys holder")
21 changes: 21 additions & 0 deletions heartbeat/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ import (
// P2PMessenger defines a subset of the p2p.Messenger interface
type P2PMessenger interface {
Broadcast(topic string, buff []byte)
BroadcastUsingPrivateKey(topic string, buff []byte, pid core.PeerID, skBytes []byte)
ID() core.PeerID
Sign(payload []byte) ([]byte, error)
SignUsingPrivateKey(skBytes []byte, payload []byte) ([]byte, error)
IsInterfaceNil() bool
}

Expand Down Expand Up @@ -120,3 +122,22 @@ type NodesCoordinator interface {
GetValidatorWithPublicKey(publicKey []byte) (validator nodesCoordinator.Validator, shardId uint32, err error)
IsInterfaceNil() bool
}

// KeysHolder defines the operations of an entity that holds virtual identities for a node
type KeysHolder interface {
AddVirtualPeer(privateKeyBytes []byte) error
GetPrivateKey(pkBytes []byte) (crypto.PrivateKey, error)
GetP2PIdentity(pkBytes []byte) ([]byte, core.PeerID, error)
GetMachineID(pkBytes []byte) (string, error)
IncrementRoundsWithoutReceivedMessages(pkBytes []byte) error
ResetRoundsWithoutReceivedMessages(pkBytes []byte) error
GetManagedKeysByCurrentNode() map[string]crypto.PrivateKey
IsKeyManagedByCurrentNode(pkBytes []byte) bool
IsKeyRegistered(pkBytes []byte) bool
IsPidManagedByCurrentNode(pid core.PeerID) bool
IsKeyValidator(pkBytes []byte) bool
SetValidatorState(pkBytes []byte, state bool)
GetNextPeerAuthenticationTime(pkBytes []byte) (time.Time, error)
SetNextPeerAuthenticationTime(pkBytes []byte, nextTime time.Time)
IsInterfaceNil() bool
}
26 changes: 22 additions & 4 deletions heartbeat/mock/messengerStub.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import (

// MessengerStub -
type MessengerStub struct {
IDCalled func() core.PeerID
BroadcastCalled func(topic string, buff []byte)
SignCalled func(payload []byte) ([]byte, error)
VerifyCalled func(payload []byte, pid core.PeerID, signature []byte) error
IDCalled func() core.PeerID
BroadcastCalled func(topic string, buff []byte)
BroadcastUsingPrivateKeyCalled func(topic string, buff []byte, pid core.PeerID, skBytes []byte)
SignCalled func(payload []byte) ([]byte, error)
SignUsingPrivateKeyCalled func(skBytes []byte, payload []byte) ([]byte, error)
VerifyCalled func(payload []byte, pid core.PeerID, signature []byte) error
}

// ID -
Expand All @@ -28,6 +30,13 @@ func (ms *MessengerStub) Broadcast(topic string, buff []byte) {
}
}

// BroadcastUsingPrivateKey -
func (ms *MessengerStub) BroadcastUsingPrivateKey(topic string, buff []byte, pid core.PeerID, skBytes []byte) {
if ms.BroadcastUsingPrivateKeyCalled != nil {
ms.BroadcastUsingPrivateKeyCalled(topic, buff, pid, skBytes)
}
}

// Sign -
func (ms *MessengerStub) Sign(payload []byte) ([]byte, error) {
if ms.SignCalled != nil {
Expand All @@ -37,6 +46,15 @@ func (ms *MessengerStub) Sign(payload []byte) ([]byte, error) {
return make([]byte, 0), nil
}

// SignUsingPrivateKey -
func (ms *MessengerStub) SignUsingPrivateKey(skBytes []byte, payload []byte) ([]byte, error) {
if ms.SignUsingPrivateKeyCalled != nil {
return ms.SignUsingPrivateKeyCalled(skBytes, payload)
}

return make([]byte, 0), nil
}

// Verify -
func (ms *MessengerStub) Verify(payload []byte, pid core.PeerID, signature []byte) error {
if ms.VerifyCalled != nil {
Expand Down
93 changes: 93 additions & 0 deletions heartbeat/sender/commonPeerAuthenticationSender.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package sender

import (
"bytes"
"time"

"github.com/ElrondNetwork/elrond-go-core/data/batch"
crypto "github.com/ElrondNetwork/elrond-go-crypto"
"github.com/ElrondNetwork/elrond-go/heartbeat"
)

type commonPeerAuthenticationSender struct {
baseSender
nodesCoordinator heartbeat.NodesCoordinator
peerSignatureHandler crypto.PeerSignatureHandler
hardforkTrigger heartbeat.HardforkTrigger
hardforkTriggerPubKey []byte
}

func (cpas *commonPeerAuthenticationSender) generateMessageBytes(
pkBytes []byte,
privateKey crypto.PrivateKey,
p2pSkBytes []byte,
pidBytes []byte,
) ([]byte, bool, error) {
msg := &heartbeat.PeerAuthentication{
Pid: pidBytes,
Pubkey: pkBytes,
}

hardforkPayload, isTriggered := cpas.getHardforkPayload()
payload := &heartbeat.Payload{
Timestamp: time.Now().Unix(),
HardforkMessage: string(hardforkPayload),
}
payloadBytes, err := cpas.marshaller.Marshal(payload)
if err != nil {
return nil, isTriggered, err
}
msg.Payload = payloadBytes

if p2pSkBytes != nil {
msg.PayloadSignature, err = cpas.messenger.SignUsingPrivateKey(p2pSkBytes, payloadBytes)
if err != nil {
return nil, isTriggered, err
}
} else {
msg.PayloadSignature, err = cpas.messenger.Sign(payloadBytes)
if err != nil {
return nil, isTriggered, err
}
}

msg.Signature, err = cpas.peerSignatureHandler.GetPeerSignature(privateKey, msg.Pid)
if err != nil {
return nil, isTriggered, err
}

msgBytes, err := cpas.marshaller.Marshal(msg)
if err != nil {
return nil, isTriggered, err
}

b := &batch.Batch{
Data: make([][]byte, 1),
}
b.Data[0] = msgBytes
data, err := cpas.marshaller.Marshal(b)
if err != nil {
return nil, isTriggered, err
}

return data, isTriggered, nil
}

func (cpas *commonPeerAuthenticationSender) isValidator(pkBytes []byte) bool {
_, _, err := cpas.nodesCoordinator.GetValidatorWithPublicKey(pkBytes)
return err == nil
}

func (cpas *commonPeerAuthenticationSender) isHardforkSource(pkBytes []byte) bool {
return bytes.Equal(pkBytes, cpas.hardforkTriggerPubKey)
}

func (cpas *commonPeerAuthenticationSender) getHardforkPayload() ([]byte, bool) {
payload := make([]byte, 0)
_, isTriggered := cpas.hardforkTrigger.RecordedTriggerMessage()
if isTriggered {
payload = cpas.hardforkTrigger.CreateData()
}

return payload, isTriggered
}