clean: squash history (binaries stripped via filter-repo)

This commit is contained in:
Hanzo AI
2026-04-13 03:45:21 -07:00
commit f6e63d60b2
2029 changed files with 465257 additions and 0 deletions
+18
View File
@@ -0,0 +1,18 @@
//go:build grpc
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package message
import "github.com/luxfi/node/proto/p2p"
// newMessageBFT creates a BFT message wrapper (gRPC version - uses Simplex)
func newMessageBFT(msg *p2p.BFT) *p2p.Message_BFT {
return &p2p.Message_BFT{Simplex: msg}
}
// extractBFT extracts the BFT message from the wrapper (gRPC version - uses Simplex)
func extractBFT(msg *p2p.Message_BFT) *p2p.BFT {
return msg.Simplex
}
+18
View File
@@ -0,0 +1,18 @@
//go:build !grpc
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package message
import "github.com/luxfi/node/proto/p2p"
// newMessageBFT creates a BFT message wrapper (ZAP version)
func newMessageBFT(msg *p2p.BFT) *p2p.Message_BFT {
return &p2p.Message_BFT{BFT: msg}
}
// extractBFT extracts the BFT message from the wrapper (ZAP version)
func extractBFT(msg *p2p.Message_BFT) *p2p.BFT {
return msg.BFT
}
+28
View File
@@ -0,0 +1,28 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package message
// Codec defines the wire format encoding interface for P2P messages.
// Implementations are selected via build tags (proto vs zap).
type Codec interface {
Marshal(msg *P2PMessage) ([]byte, error)
Unmarshal(data []byte, msg *P2PMessage) error
Size(msg *P2PMessage) int
}
// P2PMessage is the top-level message container used by the codec.
// It wraps the inner message type for encoding/decoding.
type P2PMessage struct {
inner interface{}
}
// SetInner sets the inner message
func (m *P2PMessage) SetInner(v interface{}) {
m.inner = v
}
// Inner returns the inner message
func (m *P2PMessage) Inner() interface{} {
return m.inner
}
+42
View File
@@ -0,0 +1,42 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package message
import (
"time"
"github.com/luxfi/metric"
compression "github.com/luxfi/compress"
)
var _ Creator = (*creator)(nil)
type Creator interface {
OutboundMsgBuilder
InboundMsgBuilder
}
type creator struct {
OutboundMsgBuilder
InboundMsgBuilder
}
func NewCreator(
metrics metric.Registerer,
compressionType compression.Type,
maxMessageTimeout time.Duration,
) (Creator, error) {
builder, err := newMsgBuilder(
metrics,
maxMessageTimeout,
)
if err != nil {
return nil, err
}
return &creator{
OutboundMsgBuilder: newOutboundBuilder(compressionType, builder),
InboundMsgBuilder: newInboundBuilder(builder),
}, nil
}
+115
View File
@@ -0,0 +1,115 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package message
import (
"errors"
"time"
"github.com/luxfi/ids"
"github.com/luxfi/node/proto/p2p"
)
var (
errMissingField = errors.New("message missing field")
_ chainIDGetter = (*p2p.GetStateSummaryFrontier)(nil)
_ chainIDGetter = (*p2p.StateSummaryFrontier)(nil)
_ chainIDGetter = (*p2p.GetAcceptedStateSummary)(nil)
_ chainIDGetter = (*p2p.AcceptedStateSummary)(nil)
_ chainIDGetter = (*p2p.GetAcceptedFrontier)(nil)
_ chainIDGetter = (*p2p.AcceptedFrontier)(nil)
_ chainIDGetter = (*p2p.GetAccepted)(nil)
_ chainIDGetter = (*p2p.Accepted)(nil)
_ chainIDGetter = (*p2p.GetAncestors)(nil)
_ chainIDGetter = (*p2p.Ancestors)(nil)
_ chainIDGetter = (*p2p.Get)(nil)
_ chainIDGetter = (*p2p.Put)(nil)
_ chainIDGetter = (*p2p.PushQuery)(nil)
_ chainIDGetter = (*p2p.PullQuery)(nil)
_ chainIDGetter = (*p2p.Chits)(nil)
_ chainIDGetter = (*p2p.Request)(nil)
_ chainIDGetter = (*p2p.Response)(nil)
_ chainIDGetter = (*p2p.Gossip)(nil)
_ chainIDGetter = (*p2p.BFT)(nil)
_ requestIDGetter = (*p2p.GetStateSummaryFrontier)(nil)
_ requestIDGetter = (*p2p.StateSummaryFrontier)(nil)
_ requestIDGetter = (*p2p.GetAcceptedStateSummary)(nil)
_ requestIDGetter = (*p2p.AcceptedStateSummary)(nil)
_ requestIDGetter = (*p2p.GetAcceptedFrontier)(nil)
_ requestIDGetter = (*p2p.AcceptedFrontier)(nil)
_ requestIDGetter = (*p2p.GetAccepted)(nil)
_ requestIDGetter = (*p2p.Accepted)(nil)
_ requestIDGetter = (*p2p.GetAncestors)(nil)
_ requestIDGetter = (*p2p.Ancestors)(nil)
_ requestIDGetter = (*p2p.Get)(nil)
_ requestIDGetter = (*p2p.Put)(nil)
_ requestIDGetter = (*p2p.PushQuery)(nil)
_ requestIDGetter = (*p2p.PullQuery)(nil)
_ requestIDGetter = (*p2p.Chits)(nil)
_ requestIDGetter = (*p2p.Request)(nil)
_ requestIDGetter = (*p2p.Response)(nil)
_ engineTypeGetter = (*p2p.GetAncestors)(nil)
_ deadlineGetter = (*p2p.GetStateSummaryFrontier)(nil)
_ deadlineGetter = (*p2p.GetAcceptedStateSummary)(nil)
_ deadlineGetter = (*p2p.GetAcceptedFrontier)(nil)
_ deadlineGetter = (*p2p.GetAccepted)(nil)
_ deadlineGetter = (*p2p.GetAncestors)(nil)
_ deadlineGetter = (*p2p.Get)(nil)
_ deadlineGetter = (*p2p.PushQuery)(nil)
_ deadlineGetter = (*p2p.PullQuery)(nil)
_ deadlineGetter = (*p2p.Request)(nil)
)
type chainIDGetter interface {
GetChainId() []byte
}
func GetChainID(m any) (ids.ID, error) {
msg, ok := m.(chainIDGetter)
if !ok {
return ids.Empty, errMissingField
}
chainIDBytes := msg.GetChainId()
return ids.ToID(chainIDBytes)
}
type requestIDGetter interface {
GetRequestId() uint32
}
func GetRequestID(m any) (uint32, bool) {
if msg, ok := m.(requestIDGetter); ok {
return msg.GetRequestId(), true
}
return 0, false
}
type engineTypeGetter interface {
GetEngineType() p2p.EngineType
}
func GetEngineType(m any) (p2p.EngineType, bool) {
msg, ok := m.(engineTypeGetter)
if !ok {
return p2p.EngineType_ENGINE_TYPE_UNSPECIFIED, false
}
return msg.GetEngineType(), true
}
type deadlineGetter interface {
GetDeadline() uint64
}
func GetDeadline(m any) (time.Duration, bool) {
msg, ok := m.(deadlineGetter)
if !ok {
return 0, false
}
deadline := msg.GetDeadline()
return time.Duration(deadline), true
}
+350
View File
@@ -0,0 +1,350 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package message
import (
"time"
"github.com/luxfi/ids"
"github.com/luxfi/node/proto/p2p"
"github.com/luxfi/timer/mockable"
)
var _ InboundMsgBuilder = (*inMsgBuilder)(nil)
type InboundMsgBuilder interface {
// Parse reads given bytes as InboundMessage
Parse(
bytes []byte,
nodeID ids.NodeID,
onFinishedHandling func(),
) (InboundMessage, error)
}
type inMsgBuilder struct {
builder *msgBuilder
}
func newInboundBuilder(builder *msgBuilder) InboundMsgBuilder {
return &inMsgBuilder{
builder: builder,
}
}
func (b *inMsgBuilder) Parse(bytes []byte, nodeID ids.NodeID, onFinishedHandling func()) (InboundMessage, error) {
return b.builder.parseInbound(bytes, nodeID, onFinishedHandling)
}
func InboundGetStateSummaryFrontier(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
nodeID ids.NodeID,
) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: GetStateSummaryFrontierOp,
message: &p2p.GetStateSummaryFrontier{
ChainId: chainID[:],
RequestId: requestID,
Deadline: uint64(deadline),
},
expiration: time.Now().Add(deadline),
}
}
func InboundStateSummaryFrontier(
chainID ids.ID,
requestID uint32,
summary []byte,
nodeID ids.NodeID,
) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: StateSummaryFrontierOp,
message: &p2p.StateSummaryFrontier{
ChainId: chainID[:],
RequestId: requestID,
Summary: summary,
},
expiration: mockable.MaxTime,
}
}
func InboundGetAcceptedStateSummary(
chainID ids.ID,
requestID uint32,
heights []uint64,
deadline time.Duration,
nodeID ids.NodeID,
) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: GetAcceptedStateSummaryOp,
message: &p2p.GetAcceptedStateSummary{
ChainId: chainID[:],
RequestId: requestID,
Deadline: uint64(deadline),
Heights: heights,
},
expiration: time.Now().Add(deadline),
}
}
func InboundAcceptedStateSummary(
chainID ids.ID,
requestID uint32,
summaryIDs []ids.ID,
nodeID ids.NodeID,
) InboundMessage {
summaryIDBytes := make([][]byte, len(summaryIDs))
encodeIDs(summaryIDs, summaryIDBytes)
return &inboundMessage{
nodeID: nodeID,
op: AcceptedStateSummaryOp,
message: &p2p.AcceptedStateSummary{
ChainId: chainID[:],
RequestId: requestID,
SummaryIds: summaryIDBytes,
},
expiration: mockable.MaxTime,
}
}
func InboundGetAcceptedFrontier(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
nodeID ids.NodeID,
) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: GetAcceptedFrontierOp,
message: &p2p.GetAcceptedFrontier{
ChainId: chainID[:],
RequestId: requestID,
Deadline: uint64(deadline),
},
expiration: time.Now().Add(deadline),
}
}
func InboundAcceptedFrontier(
chainID ids.ID,
requestID uint32,
containerID ids.ID,
nodeID ids.NodeID,
) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: AcceptedFrontierOp,
message: &p2p.AcceptedFrontier{
ChainId: chainID[:],
RequestId: requestID,
ContainerId: containerID[:],
},
expiration: mockable.MaxTime,
}
}
func InboundGetAccepted(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
containerIDs []ids.ID,
nodeID ids.NodeID,
) InboundMessage {
containerIDBytes := make([][]byte, len(containerIDs))
encodeIDs(containerIDs, containerIDBytes)
return &inboundMessage{
nodeID: nodeID,
op: GetAcceptedOp,
message: &p2p.GetAccepted{
ChainId: chainID[:],
RequestId: requestID,
Deadline: uint64(deadline),
ContainerIds: containerIDBytes,
},
expiration: time.Now().Add(deadline),
}
}
func InboundAccepted(
chainID ids.ID,
requestID uint32,
containerIDs []ids.ID,
nodeID ids.NodeID,
) InboundMessage {
containerIDBytes := make([][]byte, len(containerIDs))
encodeIDs(containerIDs, containerIDBytes)
return &inboundMessage{
nodeID: nodeID,
op: AcceptedOp,
message: &p2p.Accepted{
ChainId: chainID[:],
RequestId: requestID,
ContainerIds: containerIDBytes,
},
expiration: mockable.MaxTime,
}
}
func InboundPushQuery(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
container []byte,
requestedHeight uint64,
nodeID ids.NodeID,
) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: PushQueryOp,
message: &p2p.PushQuery{
ChainId: chainID[:],
RequestId: requestID,
Deadline: uint64(deadline),
Container: container,
RequestedHeight: requestedHeight,
},
expiration: time.Now().Add(deadline),
}
}
func InboundPullQuery(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
containerID ids.ID,
requestedHeight uint64,
nodeID ids.NodeID,
) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: PullQueryOp,
message: &p2p.PullQuery{
ChainId: chainID[:],
RequestId: requestID,
Deadline: uint64(deadline),
ContainerId: containerID[:],
RequestedHeight: requestedHeight,
},
expiration: time.Now().Add(deadline),
}
}
func InboundChits(
chainID ids.ID,
requestID uint32,
preferredID ids.ID,
preferredIDAtHeight ids.ID,
acceptedID ids.ID,
nodeID ids.NodeID,
) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: QbitOp,
message: &p2p.Chits{
ChainId: chainID[:],
RequestId: requestID,
PreferredId: preferredID[:],
PreferredIdAtHeight: preferredIDAtHeight[:],
AcceptedId: acceptedID[:],
},
expiration: mockable.MaxTime,
}
}
func InboundRequest(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
msg []byte,
nodeID ids.NodeID,
) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: RequestOp,
message: &p2p.Request{
ChainId: chainID[:],
RequestId: requestID,
Deadline: uint64(deadline),
AppBytes: msg,
},
expiration: time.Now().Add(deadline),
}
}
func InboundError(
nodeID ids.NodeID,
chainID ids.ID,
requestID uint32,
errorCode int32,
errorMessage string,
) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: ErrorOp,
message: &p2p.Error{
ChainId: chainID[:],
RequestId: requestID,
ErrorCode: errorCode,
ErrorMessage: errorMessage,
},
expiration: mockable.MaxTime,
}
}
func InboundResponse(
chainID ids.ID,
requestID uint32,
msg []byte,
nodeID ids.NodeID,
) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: ResponseOp,
message: &p2p.Response{
ChainId: chainID[:],
RequestId: requestID,
AppBytes: msg,
},
expiration: mockable.MaxTime,
}
}
func InboundGossip(
chainID ids.ID,
msg []byte,
nodeID ids.NodeID,
) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: GossipOp,
message: &p2p.Gossip{
ChainId: chainID[:],
AppBytes: msg,
},
expiration: mockable.MaxTime,
}
}
// NewInboundBFTMessage creates a new InboundMessage for bft messages.
func InboundBFTMessage(
nodeID ids.NodeID,
msg *p2p.BFT,
) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: BFTOp,
message: msg,
expiration: mockable.MaxTime,
}
}
func encodeIDs(ids []ids.ID, result [][]byte) {
for i, id := range ids {
result[i] = id[:]
}
}
+425
View File
@@ -0,0 +1,425 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package message
import (
"github.com/luxfi/metric"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/luxfi/ids"
"github.com/luxfi/node/proto/p2p"
"github.com/luxfi/timer/mockable"
compression "github.com/luxfi/compress"
)
func Test_newMsgBuilder(t *testing.T) {
t.Parallel()
require := require.New(t)
mb, err := newMsgBuilder(
metric.NewRegistry(),
10*time.Second,
)
require.NoError(err)
require.NotNil(mb)
}
func TestInboundMsgBuilder(t *testing.T) {
var (
chainID = ids.GenerateTestID()
requestID uint32 = 12345
deadline = time.Hour
nodeID = ids.GenerateTestNodeID()
summary = []byte{9, 8, 7}
appBytes = []byte{1, 3, 3, 7}
container = []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}
containerIDs = []ids.ID{ids.GenerateTestID(), ids.GenerateTestID()}
requestedHeight uint64 = 999
acceptedContainerID = ids.GenerateTestID()
summaryIDs = []ids.ID{ids.GenerateTestID(), ids.GenerateTestID()}
heights = []uint64{1000, 2000}
)
t.Run(
"InboundGetStateSummaryFrontier",
func(t *testing.T) {
require := require.New(t)
start := time.Now()
msg := InboundGetStateSummaryFrontier(
chainID,
requestID,
deadline,
nodeID,
)
end := time.Now()
require.Equal(GetStateSummaryFrontierOp, msg.Op())
require.Equal(nodeID, msg.NodeID())
require.False(msg.Expiration().Before(start.Add(deadline)))
require.False(end.Add(deadline).Before(msg.Expiration()))
require.IsType(&p2p.GetStateSummaryFrontier{}, msg.Message())
innerMsg := msg.Message().(*p2p.GetStateSummaryFrontier)
require.Equal(chainID[:], innerMsg.ChainId)
require.Equal(requestID, innerMsg.RequestId)
},
)
t.Run(
"InboundStateSummaryFrontier",
func(t *testing.T) {
require := require.New(t)
msg := InboundStateSummaryFrontier(
chainID,
requestID,
summary,
nodeID,
)
require.Equal(StateSummaryFrontierOp, msg.Op())
require.Equal(nodeID, msg.NodeID())
require.Equal(mockable.MaxTime, msg.Expiration())
require.IsType(&p2p.StateSummaryFrontier{}, msg.Message())
innerMsg := msg.Message().(*p2p.StateSummaryFrontier)
require.Equal(chainID[:], innerMsg.ChainId)
require.Equal(requestID, innerMsg.RequestId)
require.Equal(summary, innerMsg.Summary)
},
)
t.Run(
"InboundGetAcceptedStateSummary",
func(t *testing.T) {
require := require.New(t)
start := time.Now()
msg := InboundGetAcceptedStateSummary(
chainID,
requestID,
heights,
deadline,
nodeID,
)
end := time.Now()
require.Equal(GetAcceptedStateSummaryOp, msg.Op())
require.Equal(nodeID, msg.NodeID())
require.False(msg.Expiration().Before(start.Add(deadline)))
require.False(end.Add(deadline).Before(msg.Expiration()))
require.IsType(&p2p.GetAcceptedStateSummary{}, msg.Message())
innerMsg := msg.Message().(*p2p.GetAcceptedStateSummary)
require.Equal(chainID[:], innerMsg.ChainId)
require.Equal(requestID, innerMsg.RequestId)
require.Equal(heights, innerMsg.Heights)
},
)
t.Run(
"InboundAcceptedStateSummary",
func(t *testing.T) {
require := require.New(t)
msg := InboundAcceptedStateSummary(
chainID,
requestID,
summaryIDs,
nodeID,
)
require.Equal(AcceptedStateSummaryOp, msg.Op())
require.Equal(nodeID, msg.NodeID())
require.Equal(mockable.MaxTime, msg.Expiration())
require.IsType(&p2p.AcceptedStateSummary{}, msg.Message())
innerMsg := msg.Message().(*p2p.AcceptedStateSummary)
require.Equal(chainID[:], innerMsg.ChainId)
require.Equal(requestID, innerMsg.RequestId)
summaryIDsBytes := make([][]byte, len(summaryIDs))
for i, id := range summaryIDs {
summaryIDsBytes[i] = id[:]
}
require.Equal(summaryIDsBytes, innerMsg.SummaryIds)
},
)
t.Run(
"InboundGetAcceptedFrontier",
func(t *testing.T) {
require := require.New(t)
start := time.Now()
msg := InboundGetAcceptedFrontier(
chainID,
requestID,
deadline,
nodeID,
)
end := time.Now()
require.Equal(GetAcceptedFrontierOp, msg.Op())
require.Equal(nodeID, msg.NodeID())
require.False(msg.Expiration().Before(start.Add(deadline)))
require.False(end.Add(deadline).Before(msg.Expiration()))
require.IsType(&p2p.GetAcceptedFrontier{}, msg.Message())
innerMsg := msg.Message().(*p2p.GetAcceptedFrontier)
require.Equal(chainID[:], innerMsg.ChainId)
require.Equal(requestID, innerMsg.RequestId)
},
)
t.Run(
"InboundAcceptedFrontier",
func(t *testing.T) {
require := require.New(t)
msg := InboundAcceptedFrontier(
chainID,
requestID,
containerIDs[0],
nodeID,
)
require.Equal(AcceptedFrontierOp, msg.Op())
require.Equal(nodeID, msg.NodeID())
require.Equal(mockable.MaxTime, msg.Expiration())
require.IsType(&p2p.AcceptedFrontier{}, msg.Message())
innerMsg := msg.Message().(*p2p.AcceptedFrontier)
require.Equal(chainID[:], innerMsg.ChainId)
require.Equal(requestID, innerMsg.RequestId)
require.Equal(containerIDs[0][:], innerMsg.ContainerId)
},
)
t.Run(
"InboundGetAccepted",
func(t *testing.T) {
require := require.New(t)
start := time.Now()
msg := InboundGetAccepted(
chainID,
requestID,
deadline,
containerIDs,
nodeID,
)
end := time.Now()
require.Equal(GetAcceptedOp, msg.Op())
require.Equal(nodeID, msg.NodeID())
require.False(msg.Expiration().Before(start.Add(deadline)))
require.False(end.Add(deadline).Before(msg.Expiration()))
require.IsType(&p2p.GetAccepted{}, msg.Message())
innerMsg := msg.Message().(*p2p.GetAccepted)
require.Equal(chainID[:], innerMsg.ChainId)
require.Equal(requestID, innerMsg.RequestId)
},
)
t.Run(
"InboundAccepted",
func(t *testing.T) {
require := require.New(t)
msg := InboundAccepted(
chainID,
requestID,
containerIDs,
nodeID,
)
require.Equal(AcceptedOp, msg.Op())
require.Equal(nodeID, msg.NodeID())
require.Equal(mockable.MaxTime, msg.Expiration())
require.IsType(&p2p.Accepted{}, msg.Message())
innerMsg := msg.Message().(*p2p.Accepted)
require.Equal(chainID[:], innerMsg.ChainId)
require.Equal(requestID, innerMsg.RequestId)
containerIDsBytes := make([][]byte, len(containerIDs))
for i, id := range containerIDs {
containerIDsBytes[i] = id[:]
}
require.Equal(containerIDsBytes, innerMsg.ContainerIds)
},
)
t.Run(
"InboundPushQuery",
func(t *testing.T) {
require := require.New(t)
start := time.Now()
msg := InboundPushQuery(
chainID,
requestID,
deadline,
container,
requestedHeight,
nodeID,
)
end := time.Now()
require.Equal(PushQueryOp, msg.Op())
require.Equal(nodeID, msg.NodeID())
require.False(msg.Expiration().Before(start.Add(deadline)))
require.False(end.Add(deadline).Before(msg.Expiration()))
require.IsType(&p2p.PushQuery{}, msg.Message())
innerMsg := msg.Message().(*p2p.PushQuery)
require.Equal(chainID[:], innerMsg.ChainId)
require.Equal(requestID, innerMsg.RequestId)
require.Equal(container, innerMsg.Container)
require.Equal(requestedHeight, innerMsg.RequestedHeight)
},
)
t.Run(
"InboundPullQuery",
func(t *testing.T) {
require := require.New(t)
start := time.Now()
msg := InboundPullQuery(
chainID,
requestID,
deadline,
containerIDs[0],
requestedHeight,
nodeID,
)
end := time.Now()
require.Equal(PullQueryOp, msg.Op())
require.Equal(nodeID, msg.NodeID())
require.False(msg.Expiration().Before(start.Add(deadline)))
require.False(end.Add(deadline).Before(msg.Expiration()))
require.IsType(&p2p.PullQuery{}, msg.Message())
innerMsg := msg.Message().(*p2p.PullQuery)
require.Equal(chainID[:], innerMsg.ChainId)
require.Equal(requestID, innerMsg.RequestId)
require.Equal(containerIDs[0][:], innerMsg.ContainerId)
require.Equal(requestedHeight, innerMsg.RequestedHeight)
},
)
t.Run(
"InboundChits",
func(t *testing.T) {
require := require.New(t)
msg := InboundChits(
chainID,
requestID,
containerIDs[0],
containerIDs[1],
acceptedContainerID,
nodeID,
)
require.Equal(QbitOp, msg.Op())
require.Equal(nodeID, msg.NodeID())
require.Equal(mockable.MaxTime, msg.Expiration())
require.IsType(&p2p.Chits{}, msg.Message())
innerMsg := msg.Message().(*p2p.Chits)
require.Equal(chainID[:], innerMsg.ChainId)
require.Equal(requestID, innerMsg.RequestId)
require.Equal(containerIDs[0][:], innerMsg.PreferredId)
require.Equal(containerIDs[1][:], innerMsg.PreferredIdAtHeight)
require.Equal(acceptedContainerID[:], innerMsg.AcceptedId)
},
)
t.Run(
"InboundRequest",
func(t *testing.T) {
require := require.New(t)
start := time.Now()
msg := InboundRequest(
chainID,
requestID,
deadline,
appBytes,
nodeID,
)
end := time.Now()
require.Equal(RequestOp, msg.Op())
require.Equal(nodeID, msg.NodeID())
require.False(msg.Expiration().Before(start.Add(deadline)))
require.False(end.Add(deadline).Before(msg.Expiration()))
require.IsType(&p2p.Request{}, msg.Message())
innerMsg := msg.Message().(*p2p.Request)
require.Equal(chainID[:], innerMsg.ChainId)
require.Equal(requestID, innerMsg.RequestId)
require.Equal(appBytes, innerMsg.AppBytes)
},
)
t.Run(
"InboundResponse",
func(t *testing.T) {
require := require.New(t)
msg := InboundResponse(
chainID,
requestID,
appBytes,
nodeID,
)
require.Equal(ResponseOp, msg.Op())
require.Equal(nodeID, msg.NodeID())
require.Equal(mockable.MaxTime, msg.Expiration())
require.IsType(&p2p.Response{}, msg.Message())
innerMsg := msg.Message().(*p2p.Response)
require.Equal(chainID[:], innerMsg.ChainId)
require.Equal(requestID, innerMsg.RequestId)
require.Equal(appBytes, innerMsg.AppBytes)
},
)
}
func TestError(t *testing.T) {
require := require.New(t)
mb, err := newMsgBuilder(
metric.NewRegistry(),
time.Second,
)
require.NoError(err)
nodeID := ids.GenerateTestNodeID()
chainID := ids.GenerateTestID()
requestID := uint32(1)
errorCode := int32(2)
errorMessage := "hello world"
want := &p2p.Message{
Message: &p2p.Message_Error{
Error: &p2p.Error{
ChainId: chainID[:],
RequestId: requestID,
ErrorCode: errorCode,
ErrorMessage: errorMessage,
},
},
}
outMsg, err := mb.createOutbound(want, compression.TypeNone, false)
require.NoError(err)
got, err := mb.parseInbound(outMsg.Bytes(), nodeID, func() {})
require.NoError(err)
require.Equal(nodeID, got.NodeID())
require.Equal(ErrorOp, got.Op())
msg, ok := got.Message().(*p2p.Error)
require.True(ok)
require.Equal(errorCode, msg.ErrorCode)
require.Equal(errorMessage, msg.ErrorMessage)
}
+390
View File
@@ -0,0 +1,390 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
//nolint:staticcheck // proto generates interfaces that fail linting
package message
import (
"fmt"
"github.com/luxfi/ids"
"github.com/luxfi/node/proto/p2p"
"github.com/luxfi/node/version"
"github.com/luxfi/timer/mockable"
)
var (
disconnected = &Disconnected{}
gossipRequest = &GossipRequest{}
_ fmt.Stringer = (*GetStateSummaryFrontierFailed)(nil)
_ chainIDGetter = (*GetStateSummaryFrontierFailed)(nil)
_ requestIDGetter = (*GetStateSummaryFrontierFailed)(nil)
_ fmt.Stringer = (*GetAcceptedStateSummaryFailed)(nil)
_ chainIDGetter = (*GetAcceptedStateSummaryFailed)(nil)
_ requestIDGetter = (*GetAcceptedStateSummaryFailed)(nil)
_ fmt.Stringer = (*GetAcceptedFrontierFailed)(nil)
_ chainIDGetter = (*GetAcceptedFrontierFailed)(nil)
_ requestIDGetter = (*GetAcceptedFrontierFailed)(nil)
_ fmt.Stringer = (*GetAcceptedFailed)(nil)
_ chainIDGetter = (*GetAcceptedFailed)(nil)
_ requestIDGetter = (*GetAcceptedFailed)(nil)
_ fmt.Stringer = (*GetAncestorsFailed)(nil)
_ chainIDGetter = (*GetAncestorsFailed)(nil)
_ requestIDGetter = (*GetAncestorsFailed)(nil)
_ engineTypeGetter = (*GetAncestorsFailed)(nil)
_ fmt.Stringer = (*GetFailed)(nil)
_ chainIDGetter = (*GetFailed)(nil)
_ requestIDGetter = (*GetFailed)(nil)
_ fmt.Stringer = (*QueryFailed)(nil)
_ chainIDGetter = (*QueryFailed)(nil)
_ requestIDGetter = (*QueryFailed)(nil)
_ fmt.Stringer = (*Disconnected)(nil)
_ fmt.Stringer = (*GossipRequest)(nil)
)
type GetStateSummaryFrontierFailed struct {
ChainID ids.ID `json:"chain_id,omitempty"`
RequestID uint32 `json:"request_id,omitempty"`
}
func (m *GetStateSummaryFrontierFailed) String() string {
return fmt.Sprintf(
"ChainID: %s RequestID: %d",
m.ChainID, m.RequestID,
)
}
func (m *GetStateSummaryFrontierFailed) GetChainId() []byte {
return m.ChainID[:]
}
func (m *GetStateSummaryFrontierFailed) GetRequestId() uint32 {
return m.RequestID
}
func InternalGetStateSummaryFrontierFailed(
nodeID ids.NodeID,
chainID ids.ID,
requestID uint32,
) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: GetStateSummaryFrontierFailedOp,
message: &GetStateSummaryFrontierFailed{
ChainID: chainID,
RequestID: requestID,
},
expiration: mockable.MaxTime,
}
}
type GetAcceptedStateSummaryFailed struct {
ChainID ids.ID `json:"chain_id,omitempty"`
RequestID uint32 `json:"request_id,omitempty"`
}
func (m *GetAcceptedStateSummaryFailed) String() string {
return fmt.Sprintf(
"ChainID: %s RequestID: %d",
m.ChainID, m.RequestID,
)
}
func (m *GetAcceptedStateSummaryFailed) GetChainId() []byte {
return m.ChainID[:]
}
func (m *GetAcceptedStateSummaryFailed) GetRequestId() uint32 {
return m.RequestID
}
func InternalGetAcceptedStateSummaryFailed(
nodeID ids.NodeID,
chainID ids.ID,
requestID uint32,
) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: GetAcceptedStateSummaryFailedOp,
message: &GetAcceptedStateSummaryFailed{
ChainID: chainID,
RequestID: requestID,
},
expiration: mockable.MaxTime,
}
}
type GetAcceptedFrontierFailed struct {
ChainID ids.ID `json:"chain_id,omitempty"`
RequestID uint32 `json:"request_id,omitempty"`
}
func (m *GetAcceptedFrontierFailed) String() string {
return fmt.Sprintf(
"ChainID: %s RequestID: %d",
m.ChainID, m.RequestID,
)
}
func (m *GetAcceptedFrontierFailed) GetChainId() []byte {
return m.ChainID[:]
}
func (m *GetAcceptedFrontierFailed) GetRequestId() uint32 {
return m.RequestID
}
func InternalGetAcceptedFrontierFailed(
nodeID ids.NodeID,
chainID ids.ID,
requestID uint32,
) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: GetAcceptedFrontierFailedOp,
message: &GetAcceptedFrontierFailed{
ChainID: chainID,
RequestID: requestID,
},
expiration: mockable.MaxTime,
}
}
type GetAcceptedFailed struct {
ChainID ids.ID `json:"chain_id,omitempty"`
RequestID uint32 `json:"request_id,omitempty"`
}
func (m *GetAcceptedFailed) String() string {
return fmt.Sprintf(
"ChainID: %s RequestID: %d",
m.ChainID, m.RequestID,
)
}
func (m *GetAcceptedFailed) GetChainId() []byte {
return m.ChainID[:]
}
func (m *GetAcceptedFailed) GetRequestId() uint32 {
return m.RequestID
}
func InternalGetAcceptedFailed(
nodeID ids.NodeID,
chainID ids.ID,
requestID uint32,
) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: GetAcceptedFailedOp,
message: &GetAcceptedFailed{
ChainID: chainID,
RequestID: requestID,
},
expiration: mockable.MaxTime,
}
}
type GetAncestorsFailed struct {
ChainID ids.ID `json:"chain_id,omitempty"`
RequestID uint32 `json:"request_id,omitempty"`
EngineType p2p.EngineType `json:"engine_type,omitempty"`
}
func (m *GetAncestorsFailed) String() string {
return fmt.Sprintf(
"ChainID: %s RequestID: %d EngineType: %s",
m.ChainID, m.RequestID, m.EngineType,
)
}
func (m *GetAncestorsFailed) GetChainId() []byte {
return m.ChainID[:]
}
func (m *GetAncestorsFailed) GetRequestId() uint32 {
return m.RequestID
}
func (m *GetAncestorsFailed) GetEngineType() p2p.EngineType {
return m.EngineType
}
func InternalGetAncestorsFailed(
nodeID ids.NodeID,
chainID ids.ID,
requestID uint32,
engineType p2p.EngineType,
) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: GetAncestorsFailedOp,
message: &GetAncestorsFailed{
ChainID: chainID,
RequestID: requestID,
EngineType: engineType,
},
expiration: mockable.MaxTime,
}
}
type GetFailed struct {
ChainID ids.ID `json:"chain_id,omitempty"`
RequestID uint32 `json:"request_id,omitempty"`
}
func (m *GetFailed) String() string {
return fmt.Sprintf(
"ChainID: %s RequestID: %d",
m.ChainID, m.RequestID,
)
}
func (m *GetFailed) GetChainId() []byte {
return m.ChainID[:]
}
func (m *GetFailed) GetRequestId() uint32 {
return m.RequestID
}
func InternalGetFailed(
nodeID ids.NodeID,
chainID ids.ID,
requestID uint32,
) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: GetFailedOp,
message: &GetFailed{
ChainID: chainID,
RequestID: requestID,
},
expiration: mockable.MaxTime,
}
}
type QueryFailed struct {
ChainID ids.ID `json:"chain_id,omitempty"`
RequestID uint32 `json:"request_id,omitempty"`
}
func (m *QueryFailed) String() string {
return fmt.Sprintf(
"ChainID: %s RequestID: %d",
m.ChainID, m.RequestID,
)
}
func (m *QueryFailed) GetChainId() []byte {
return m.ChainID[:]
}
func (m *QueryFailed) GetRequestId() uint32 {
return m.RequestID
}
func InternalQueryFailed(
nodeID ids.NodeID,
chainID ids.ID,
requestID uint32,
) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: QueryFailedOp,
message: &QueryFailed{
ChainID: chainID,
RequestID: requestID,
},
expiration: mockable.MaxTime,
}
}
type Connected struct {
NodeVersion *version.Application `json:"node_version,omitempty"`
}
func (m *Connected) String() string {
return fmt.Sprintf(
"NodeVersion: %s",
m.NodeVersion,
)
}
func InternalConnected(nodeID ids.NodeID, nodeVersion *version.Application) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: ConnectedOp,
message: &Connected{
NodeVersion: nodeVersion,
},
expiration: mockable.MaxTime,
}
}
type Disconnected struct{}
func (Disconnected) String() string {
return ""
}
func InternalDisconnected(nodeID ids.NodeID) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: DisconnectedOp,
message: disconnected,
expiration: mockable.MaxTime,
}
}
type VMMessage struct {
Notification uint32 `json:"notification,omitempty"`
}
func (m *VMMessage) String() string {
return fmt.Sprintf(
"Notification: %d",
m.Notification,
)
}
func InternalVMMessage(
nodeID ids.NodeID,
notification uint32,
) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: NotifyOp,
message: &VMMessage{
Notification: notification,
},
expiration: mockable.MaxTime,
}
}
type GossipRequest struct{}
func (GossipRequest) String() string {
return ""
}
func InternalGossipRequest(
nodeID ids.NodeID,
) InboundMessage {
return &inboundMessage{
nodeID: nodeID,
op: GossipRequestOp,
message: gossipRequest,
expiration: mockable.MaxTime,
}
}
+97
View File
@@ -0,0 +1,97 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/luxfi/node/message (interfaces: OutboundMessage)
//
// Generated by this command:
//
// mockgen -package=messagemock -destination=messagemock/outbound_message.go -mock_names=OutboundMessage=OutboundMessage . OutboundMessage
//
// Package messagemock is a generated GoMock package.
package messagemock
import (
reflect "reflect"
message "github.com/luxfi/node/message"
gomock "go.uber.org/mock/gomock"
)
// OutboundMessage is a mock of OutboundMessage interface.
type OutboundMessage struct {
ctrl *gomock.Controller
recorder *OutboundMessageMockRecorder
isgomock struct{}
}
// OutboundMessageMockRecorder is the mock recorder for OutboundMessage.
type OutboundMessageMockRecorder struct {
mock *OutboundMessage
}
// NewOutboundMessage creates a new mock instance.
func NewOutboundMessage(ctrl *gomock.Controller) *OutboundMessage {
mock := &OutboundMessage{ctrl: ctrl}
mock.recorder = &OutboundMessageMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *OutboundMessage) EXPECT() *OutboundMessageMockRecorder {
return m.recorder
}
// BypassThrottling mocks base method.
func (m *OutboundMessage) BypassThrottling() bool {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BypassThrottling")
ret0, _ := ret[0].(bool)
return ret0
}
// BypassThrottling indicates an expected call of BypassThrottling.
func (mr *OutboundMessageMockRecorder) BypassThrottling() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BypassThrottling", reflect.TypeOf((*OutboundMessage)(nil).BypassThrottling))
}
// Bytes mocks base method.
func (m *OutboundMessage) Bytes() []byte {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Bytes")
ret0, _ := ret[0].([]byte)
return ret0
}
// Bytes indicates an expected call of Bytes.
func (mr *OutboundMessageMockRecorder) Bytes() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Bytes", reflect.TypeOf((*OutboundMessage)(nil).Bytes))
}
// BytesSavedCompression mocks base method.
func (m *OutboundMessage) BytesSavedCompression() int {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BytesSavedCompression")
ret0, _ := ret[0].(int)
return ret0
}
// BytesSavedCompression indicates an expected call of BytesSavedCompression.
func (mr *OutboundMessageMockRecorder) BytesSavedCompression() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BytesSavedCompression", reflect.TypeOf((*OutboundMessage)(nil).BytesSavedCompression))
}
// Op mocks base method.
func (m *OutboundMessage) Op() message.Op {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Op")
ret0, _ := ret[0].(message.Op)
return ret0
}
// Op indicates an expected call of Op.
func (mr *OutboundMessageMockRecorder) Op() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Op", reflect.TypeOf((*OutboundMessage)(nil).Op))
}
@@ -0,0 +1,421 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/luxfi/node/message (interfaces: OutboundMsgBuilder)
//
// Generated by this command:
//
// mockgen -package=messagemock -destination=messagemock/outbound_message_builder.go -mock_names=OutboundMsgBuilder=OutboundMsgBuilder . OutboundMsgBuilder
//
// Package messagemock is a generated GoMock package.
package messagemock
import (
netip "net/netip"
reflect "reflect"
time "time"
ids "github.com/luxfi/ids"
message "github.com/luxfi/node/message"
p2p "github.com/luxfi/node/proto/p2p"
"github.com/luxfi/net/endpoints"
gomock "go.uber.org/mock/gomock"
)
// OutboundMsgBuilder is a mock of OutboundMsgBuilder interface.
type OutboundMsgBuilder struct {
ctrl *gomock.Controller
recorder *OutboundMsgBuilderMockRecorder
isgomock struct{}
}
// OutboundMsgBuilderMockRecorder is the mock recorder for OutboundMsgBuilder.
type OutboundMsgBuilderMockRecorder struct {
mock *OutboundMsgBuilder
}
// NewOutboundMsgBuilder creates a new mock instance.
func NewOutboundMsgBuilder(ctrl *gomock.Controller) *OutboundMsgBuilder {
mock := &OutboundMsgBuilder{ctrl: ctrl}
mock.recorder = &OutboundMsgBuilderMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *OutboundMsgBuilder) EXPECT() *OutboundMsgBuilderMockRecorder {
return m.recorder
}
// Accepted mocks base method.
func (m *OutboundMsgBuilder) Accepted(chainID ids.ID, requestID uint32, containerIDs []ids.ID) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Accepted", chainID, requestID, containerIDs)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Accepted indicates an expected call of Accepted.
func (mr *OutboundMsgBuilderMockRecorder) Accepted(chainID, requestID, containerIDs any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Accepted", reflect.TypeOf((*OutboundMsgBuilder)(nil).Accepted), chainID, requestID, containerIDs)
}
// AcceptedFrontier mocks base method.
func (m *OutboundMsgBuilder) AcceptedFrontier(chainID ids.ID, requestID uint32, containerID ids.ID) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AcceptedFrontier", chainID, requestID, containerID)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AcceptedFrontier indicates an expected call of AcceptedFrontier.
func (mr *OutboundMsgBuilderMockRecorder) AcceptedFrontier(chainID, requestID, containerID any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AcceptedFrontier", reflect.TypeOf((*OutboundMsgBuilder)(nil).AcceptedFrontier), chainID, requestID, containerID)
}
// AcceptedStateSummary mocks base method.
func (m *OutboundMsgBuilder) AcceptedStateSummary(chainID ids.ID, requestID uint32, summaryIDs []ids.ID) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AcceptedStateSummary", chainID, requestID, summaryIDs)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AcceptedStateSummary indicates an expected call of AcceptedStateSummary.
func (mr *OutboundMsgBuilderMockRecorder) AcceptedStateSummary(chainID, requestID, summaryIDs any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AcceptedStateSummary", reflect.TypeOf((*OutboundMsgBuilder)(nil).AcceptedStateSummary), chainID, requestID, summaryIDs)
}
// Ancestors mocks base method.
func (m *OutboundMsgBuilder) Ancestors(chainID ids.ID, requestID uint32, containers [][]byte) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Ancestors", chainID, requestID, containers)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Ancestors indicates an expected call of Ancestors.
func (mr *OutboundMsgBuilderMockRecorder) Ancestors(chainID, requestID, containers any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ancestors", reflect.TypeOf((*OutboundMsgBuilder)(nil).Ancestors), chainID, requestID, containers)
}
// Error mocks base method.
func (m *OutboundMsgBuilder) Error(chainID ids.ID, requestID uint32, errorCode int32, errorMessage string) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Error", chainID, requestID, errorCode, errorMessage)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Error indicates an expected call of Error.
func (mr *OutboundMsgBuilderMockRecorder) Error(chainID, requestID, errorCode, errorMessage any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*OutboundMsgBuilder)(nil).Error), chainID, requestID, errorCode, errorMessage)
}
// Gossip mocks base method.
func (m *OutboundMsgBuilder) Gossip(chainID ids.ID, msg []byte) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Gossip", chainID, msg)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Gossip indicates an expected call of Gossip.
func (mr *OutboundMsgBuilderMockRecorder) Gossip(chainID, msg any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Gossip", reflect.TypeOf((*OutboundMsgBuilder)(nil).Gossip), chainID, msg)
}
// Request mocks base method.
func (m *OutboundMsgBuilder) Request(chainID ids.ID, requestID uint32, deadline time.Duration, msg []byte) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Request", chainID, requestID, deadline, msg)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Request indicates an expected call of Request.
func (mr *OutboundMsgBuilderMockRecorder) Request(chainID, requestID, deadline, msg any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Request", reflect.TypeOf((*OutboundMsgBuilder)(nil).Request), chainID, requestID, deadline, msg)
}
// Response mocks base method.
func (m *OutboundMsgBuilder) Response(chainID ids.ID, requestID uint32, msg []byte) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Response", chainID, requestID, msg)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Response indicates an expected call of Response.
func (mr *OutboundMsgBuilderMockRecorder) Response(chainID, requestID, msg any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Response", reflect.TypeOf((*OutboundMsgBuilder)(nil).Response), chainID, requestID, msg)
}
// Chits mocks base method.
func (m *OutboundMsgBuilder) Chits(chainID ids.ID, requestID uint32, preferredID, preferredIDAtHeight, acceptedID ids.ID, acceptedHeight uint64) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Chits", chainID, requestID, preferredID, preferredIDAtHeight, acceptedID, acceptedHeight)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Chits indicates an expected call of Chits.
func (mr *OutboundMsgBuilderMockRecorder) Chits(chainID, requestID, preferredID, preferredIDAtHeight, acceptedID, acceptedHeight any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Chits", reflect.TypeOf((*OutboundMsgBuilder)(nil).Chits), chainID, requestID, preferredID, preferredIDAtHeight, acceptedID, acceptedHeight)
}
// Get mocks base method.
func (m *OutboundMsgBuilder) Get(chainID ids.ID, requestID uint32, deadline time.Duration, containerID ids.ID) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Get", chainID, requestID, deadline, containerID)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Get indicates an expected call of Get.
func (mr *OutboundMsgBuilderMockRecorder) Get(chainID, requestID, deadline, containerID any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*OutboundMsgBuilder)(nil).Get), chainID, requestID, deadline, containerID)
}
// GetAccepted mocks base method.
func (m *OutboundMsgBuilder) GetAccepted(chainID ids.ID, requestID uint32, deadline time.Duration, containerIDs []ids.ID) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetAccepted", chainID, requestID, deadline, containerIDs)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetAccepted indicates an expected call of GetAccepted.
func (mr *OutboundMsgBuilderMockRecorder) GetAccepted(chainID, requestID, deadline, containerIDs any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccepted", reflect.TypeOf((*OutboundMsgBuilder)(nil).GetAccepted), chainID, requestID, deadline, containerIDs)
}
// GetAcceptedFrontier mocks base method.
func (m *OutboundMsgBuilder) GetAcceptedFrontier(chainID ids.ID, requestID uint32, deadline time.Duration) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetAcceptedFrontier", chainID, requestID, deadline)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetAcceptedFrontier indicates an expected call of GetAcceptedFrontier.
func (mr *OutboundMsgBuilderMockRecorder) GetAcceptedFrontier(chainID, requestID, deadline any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAcceptedFrontier", reflect.TypeOf((*OutboundMsgBuilder)(nil).GetAcceptedFrontier), chainID, requestID, deadline)
}
// GetAcceptedStateSummary mocks base method.
func (m *OutboundMsgBuilder) GetAcceptedStateSummary(chainID ids.ID, requestID uint32, deadline time.Duration, heights []uint64) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetAcceptedStateSummary", chainID, requestID, deadline, heights)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetAcceptedStateSummary indicates an expected call of GetAcceptedStateSummary.
func (mr *OutboundMsgBuilderMockRecorder) GetAcceptedStateSummary(chainID, requestID, deadline, heights any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAcceptedStateSummary", reflect.TypeOf((*OutboundMsgBuilder)(nil).GetAcceptedStateSummary), chainID, requestID, deadline, heights)
}
// GetAncestors mocks base method.
func (m *OutboundMsgBuilder) GetAncestors(chainID ids.ID, requestID uint32, deadline time.Duration, containerID ids.ID, engineType p2p.EngineType) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetAncestors", chainID, requestID, deadline, containerID, engineType)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetAncestors indicates an expected call of GetAncestors.
func (mr *OutboundMsgBuilderMockRecorder) GetAncestors(chainID, requestID, deadline, containerID, engineType any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAncestors", reflect.TypeOf((*OutboundMsgBuilder)(nil).GetAncestors), chainID, requestID, deadline, containerID, engineType)
}
// GetPeerList mocks base method.
func (m *OutboundMsgBuilder) GetPeerList(knownPeersFilter, knownPeersSalt []byte, requestAllNetIPs bool) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetPeerList", knownPeersFilter, knownPeersSalt, requestAllNetIPs)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetPeerList indicates an expected call of GetPeerList.
func (mr *OutboundMsgBuilderMockRecorder) GetPeerList(knownPeersFilter, knownPeersSalt, requestAllNetIPs any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPeerList", reflect.TypeOf((*OutboundMsgBuilder)(nil).GetPeerList), knownPeersFilter, knownPeersSalt, requestAllNetIPs)
}
// GetStateSummaryFrontier mocks base method.
func (m *OutboundMsgBuilder) GetStateSummaryFrontier(chainID ids.ID, requestID uint32, deadline time.Duration) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetStateSummaryFrontier", chainID, requestID, deadline)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetStateSummaryFrontier indicates an expected call of GetStateSummaryFrontier.
func (mr *OutboundMsgBuilderMockRecorder) GetStateSummaryFrontier(chainID, requestID, deadline any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStateSummaryFrontier", reflect.TypeOf((*OutboundMsgBuilder)(nil).GetStateSummaryFrontier), chainID, requestID, deadline)
}
// Handshake mocks base method.
func (m *OutboundMsgBuilder) Handshake(networkID uint32, myTime uint64, ip netip.AddrPort, client string, major, minor, patch uint32, ipSigningTime uint64, ipNodeIDSig, ipBLSSig []byte, trackedNets []ids.ID, supportedLPs, objectedLPs []uint32, knownPeersFilter, knownPeersSalt []byte, requestAllNetIPs bool) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Handshake", networkID, myTime, ip, client, major, minor, patch, ipSigningTime, ipNodeIDSig, ipBLSSig, trackedNets, supportedLPs, objectedLPs, knownPeersFilter, knownPeersSalt, requestAllNetIPs)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Handshake indicates an expected call of Handshake.
func (mr *OutboundMsgBuilderMockRecorder) Handshake(networkID, myTime, ip, client, major, minor, patch, ipSigningTime, ipNodeIDSig, ipBLSSig, trackedNets, supportedLPs, objectedLPs, knownPeersFilter, knownPeersSalt, requestAllNetIPs any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Handshake", reflect.TypeOf((*OutboundMsgBuilder)(nil).Handshake), networkID, myTime, ip, client, major, minor, patch, ipSigningTime, ipNodeIDSig, ipBLSSig, trackedNets, supportedLPs, objectedLPs, knownPeersFilter, knownPeersSalt, requestAllNetIPs)
}
// PeerList mocks base method.
func (m *OutboundMsgBuilder) PeerList(peers []*endpoints.ClaimedIPPort, bypassThrottling bool) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PeerList", peers, bypassThrottling)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// PeerList indicates an expected call of PeerList.
func (mr *OutboundMsgBuilderMockRecorder) PeerList(peers, bypassThrottling any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PeerList", reflect.TypeOf((*OutboundMsgBuilder)(nil).PeerList), peers, bypassThrottling)
}
// Ping mocks base method.
func (m *OutboundMsgBuilder) Ping(primaryUptime uint32) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Ping", primaryUptime)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Ping indicates an expected call of Ping.
func (mr *OutboundMsgBuilderMockRecorder) Ping(primaryUptime any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ping", reflect.TypeOf((*OutboundMsgBuilder)(nil).Ping), primaryUptime)
}
// Pong mocks base method.
func (m *OutboundMsgBuilder) Pong() (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Pong")
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Pong indicates an expected call of Pong.
func (mr *OutboundMsgBuilderMockRecorder) Pong() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Pong", reflect.TypeOf((*OutboundMsgBuilder)(nil).Pong))
}
// PullQuery mocks base method.
func (m *OutboundMsgBuilder) PullQuery(chainID ids.ID, requestID uint32, deadline time.Duration, containerID ids.ID, requestedHeight uint64) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PullQuery", chainID, requestID, deadline, containerID, requestedHeight)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// PullQuery indicates an expected call of PullQuery.
func (mr *OutboundMsgBuilderMockRecorder) PullQuery(chainID, requestID, deadline, containerID, requestedHeight any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PullQuery", reflect.TypeOf((*OutboundMsgBuilder)(nil).PullQuery), chainID, requestID, deadline, containerID, requestedHeight)
}
// PushQuery mocks base method.
func (m *OutboundMsgBuilder) PushQuery(chainID ids.ID, requestID uint32, deadline time.Duration, container []byte, requestedHeight uint64) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PushQuery", chainID, requestID, deadline, container, requestedHeight)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// PushQuery indicates an expected call of PushQuery.
func (mr *OutboundMsgBuilderMockRecorder) PushQuery(chainID, requestID, deadline, container, requestedHeight any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PushQuery", reflect.TypeOf((*OutboundMsgBuilder)(nil).PushQuery), chainID, requestID, deadline, container, requestedHeight)
}
// Put mocks base method.
func (m *OutboundMsgBuilder) Put(chainID ids.ID, requestID uint32, container []byte) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Put", chainID, requestID, container)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Put indicates an expected call of Put.
func (mr *OutboundMsgBuilderMockRecorder) Put(chainID, requestID, container any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*OutboundMsgBuilder)(nil).Put), chainID, requestID, container)
}
// BFTMessage mocks base method.
func (m *OutboundMsgBuilder) BFTMessage(msg *p2p.BFT) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BFTMessage", msg)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// BFTMessage indicates an expected call of BFTMessage.
func (mr *OutboundMsgBuilderMockRecorder) BFTMessage(msg any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BFTMessage", reflect.TypeOf((*OutboundMsgBuilder)(nil).BFTMessage), msg)
}
// StateSummaryFrontier mocks base method.
func (m *OutboundMsgBuilder) StateSummaryFrontier(chainID ids.ID, requestID uint32, summary []byte) (message.OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "StateSummaryFrontier", chainID, requestID, summary)
ret0, _ := ret[0].(message.OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// StateSummaryFrontier indicates an expected call of StateSummaryFrontier.
func (mr *OutboundMsgBuilderMockRecorder) StateSummaryFrontier(chainID, requestID, summary any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateSummaryFrontier", reflect.TypeOf((*OutboundMsgBuilder)(nil).StateSummaryFrontier), chainID, requestID, summary)
}
+328
View File
@@ -0,0 +1,328 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package message
import (
"errors"
"fmt"
"time"
"github.com/luxfi/constants"
"github.com/luxfi/ids"
"github.com/luxfi/metric"
"github.com/luxfi/node/proto/p2p"
"github.com/luxfi/timer/mockable"
compression "github.com/luxfi/compress"
)
const (
typeLabel = "type"
opLabel = "op"
directionLabel = "direction"
compressionLabel = "compression"
decompressionLabel = "decompression"
)
var (
_ InboundMessage = (*inboundMessage)(nil)
_ OutboundMessage = (*outboundMessage)(nil)
metricLabels = []string{typeLabel, opLabel, directionLabel}
errUnknownCompressionType = errors.New("message is compressed with an unknown compression type")
)
// InboundMessage represents a set of fields for an inbound message
type InboundMessage interface {
fmt.Stringer
// NodeID returns the ID of the node that sent this message
NodeID() ids.NodeID
// Op returns the op that describes this message type
Op() Op
// Message returns the message that was sent
Message() fmt.Stringer
// Expiration returns the time that the sender will have already timed out
// this request
Expiration() time.Time
// OnFinishedHandling must be called one time when this message has been
// handled by the message handler
OnFinishedHandling()
// BytesSavedCompression returns the number of bytes that this message saved
// due to being compressed
BytesSavedCompression() int
}
type inboundMessage struct {
nodeID ids.NodeID
op Op
message fmt.Stringer
expiration time.Time
onFinishedHandling func()
bytesSavedCompression int
}
func (m *inboundMessage) NodeID() ids.NodeID {
return m.nodeID
}
func (m *inboundMessage) Op() Op {
return m.op
}
func (m *inboundMessage) Message() fmt.Stringer {
return m.message
}
func (m *inboundMessage) Expiration() time.Time {
return m.expiration
}
func (m *inboundMessage) OnFinishedHandling() {
if m.onFinishedHandling != nil {
m.onFinishedHandling()
}
}
func (m *inboundMessage) BytesSavedCompression() int {
return m.bytesSavedCompression
}
func (m *inboundMessage) String() string {
return fmt.Sprintf("%s Op: %s Message: %s",
m.nodeID, m.op, m.message)
}
// OutboundMessage represents a set of fields for an outbound message that can
// be serialized into a byte stream
type OutboundMessage interface {
// BypassThrottling returns true if we should send this message, regardless
// of any outbound message throttling
BypassThrottling() bool
// Op returns the op that describes this message type
Op() Op
// Bytes returns the bytes that will be sent
Bytes() []byte
// BytesSavedCompression returns the number of bytes that this message saved
// due to being compressed
BytesSavedCompression() int
}
type outboundMessage struct {
bypassThrottling bool
op Op
bytes []byte
bytesSavedCompression int
}
func (m *outboundMessage) BypassThrottling() bool {
return m.bypassThrottling
}
func (m *outboundMessage) Op() Op {
return m.op
}
func (m *outboundMessage) Bytes() []byte {
return m.bytes
}
func (m *outboundMessage) BytesSavedCompression() int {
return m.bytesSavedCompression
}
type msgBuilder struct {
zstdCompressor compression.Compressor
count metric.CounterVec // type + op + direction
duration metric.GaugeVec // type + op + direction
maxMessageTimeout time.Duration
}
func newMsgBuilder(
metrics metric.Registerer,
maxMessageTimeout time.Duration,
) (*msgBuilder, error) {
zstdCompressor, err := compression.NewZstdCompressor(constants.DefaultMaxMessageSize)
if err != nil {
return nil, err
}
mb := &msgBuilder{
zstdCompressor: zstdCompressor,
count: metric.NewCounterVec(
metric.CounterOpts{
Name: "codec_compressed_count",
Help: "number of compressed messages",
},
metricLabels,
),
duration: metric.NewGaugeVec(
metric.GaugeOpts{
Name: "codec_compressed_duration",
Help: "time spent handling compressed messages",
},
metricLabels,
),
maxMessageTimeout: maxMessageTimeout,
}
return mb, nil
}
func (mb *msgBuilder) marshal(
uncompressedMsg *p2p.Message,
compressionType compression.Type,
) ([]byte, int, Op, error) {
uncompressedMsgBytes, err := p2p.Marshal(uncompressedMsg)
if err != nil {
return nil, 0, 0, err
}
op, err := ToOp(uncompressedMsg)
if err != nil {
return nil, 0, 0, err
}
// If compression is enabled, we marshal twice:
// 1. the original message
// 2. the message with compressed bytes
//
// This recursive packing allows us to avoid an extra compression on/off
// field in the message.
var (
startTime = time.Now()
compressedMsg p2p.Message
)
switch compressionType {
case compression.TypeNone:
return uncompressedMsgBytes, 0, op, nil
case compression.TypeZstd:
compressedBytes, err := mb.zstdCompressor.Compress(uncompressedMsgBytes)
if err != nil {
return nil, 0, 0, err
}
compressedMsg = p2p.Message{
Message: &p2p.Message_CompressedZstd{
CompressedZstd: compressedBytes,
},
}
default:
return nil, 0, 0, errUnknownCompressionType
}
compressedMsgBytes, err := p2p.Marshal(&compressedMsg)
if err != nil {
return nil, 0, 0, err
}
compressTook := time.Since(startTime)
labels := metric.Labels{
typeLabel: compressionType.String(),
opLabel: op.String(),
directionLabel: compressionLabel,
}
mb.count.With(labels).Inc()
mb.duration.With(labels).Add(float64(compressTook))
bytesSaved := len(uncompressedMsgBytes) - len(compressedMsgBytes)
return compressedMsgBytes, bytesSaved, op, nil
}
func (mb *msgBuilder) unmarshal(b []byte) (*p2p.Message, int, Op, error) {
m := new(p2p.Message)
if err := p2p.Unmarshal(b, m); err != nil {
return nil, 0, 0, err
}
// Figure out what compression type, if any, was used to compress the message.
var (
compressor compression.Compressor
compressedBytes []byte
zstdCompressed = m.GetCompressedZstd()
)
switch {
case len(zstdCompressed) > 0:
compressor = mb.zstdCompressor
compressedBytes = zstdCompressed
default:
// The message wasn't compressed
op, err := ToOp(m)
return m, 0, op, err
}
startTime := time.Now()
decompressed, err := compressor.Decompress(compressedBytes)
if err != nil {
return nil, 0, 0, err
}
bytesSavedCompression := len(decompressed) - len(compressedBytes)
if err := p2p.Unmarshal(decompressed, m); err != nil {
return nil, 0, 0, err
}
decompressTook := time.Since(startTime)
// Record decompression time metrics
op, err := ToOp(m)
if err != nil {
return nil, 0, 0, err
}
labels := metric.Labels{
typeLabel: compression.TypeZstd.String(),
opLabel: op.String(),
directionLabel: decompressionLabel,
}
mb.count.With(labels).Inc()
mb.duration.With(labels).Add(float64(decompressTook))
return m, bytesSavedCompression, op, nil
}
func (mb *msgBuilder) createOutbound(m *p2p.Message, compressionType compression.Type, bypassThrottling bool) (*outboundMessage, error) {
b, saved, op, err := mb.marshal(m, compressionType)
if err != nil {
return nil, err
}
return &outboundMessage{
bypassThrottling: bypassThrottling,
op: op,
bytes: b,
bytesSavedCompression: saved,
}, nil
}
func (mb *msgBuilder) parseInbound(
bytes []byte,
nodeID ids.NodeID,
onFinishedHandling func(),
) (*inboundMessage, error) {
m, bytesSavedCompression, op, err := mb.unmarshal(bytes)
if err != nil {
return nil, err
}
msg, err := Unwrap(m)
if err != nil {
return nil, err
}
expiration := mockable.MaxTime
if deadline, ok := GetDeadline(msg); ok {
deadline = min(deadline, mb.maxMessageTimeout)
expiration = time.Now().Add(deadline)
}
return &inboundMessage{
nodeID: nodeID,
op: op,
message: msg,
expiration: expiration,
onFinishedHandling: onFinishedHandling,
bytesSavedCompression: bytesSavedCompression,
}, nil
}
+133
View File
@@ -0,0 +1,133 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package message
import (
"github.com/luxfi/metric"
"net"
"os"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/luxfi/ids"
"github.com/luxfi/node/proto/p2p"
compression "github.com/luxfi/compress"
)
var (
dummyNodeID = ids.EmptyNodeID
dummyOnFinishedHandling = func() {}
)
// Benchmarks marshal-ing "Handshake" message.
//
// e.g.,
//
// $ go install -v golang.org/x/tools/cmd/benchcmp@latest
// $ go install -v golang.org/x/perf/cmd/benchstat@latest
//
// $ go test -run=NONE -bench=BenchmarkMarshalHandshake > /tmp/cpu.before.txt
// $ USE_BUILDER=true go test -run=NONE -bench=BenchmarkMarshalHandshake > /tmp/cpu.after.txt
// $ benchcmp /tmp/cpu.before.txt /tmp/cpu.after.txt
// $ benchstat -alpha 0.03 -geomean /tmp/cpu.before.txt /tmp/cpu.after.txt
//
// $ go test -run=NONE -bench=BenchmarkMarshalHandshake -benchmem > /tmp/mem.before.txt
// $ USE_BUILDER=true go test -run=NONE -bench=BenchmarkMarshalHandshake -benchmem > /tmp/mem.after.txt
// $ benchcmp /tmp/mem.before.txt /tmp/mem.after.txt
// $ benchstat -alpha 0.03 -geomean /tmp/mem.before.txt /tmp/mem.after.txt
func BenchmarkMarshalHandshake(b *testing.B) {
require := require.New(b)
id := ids.GenerateTestID()
msg := p2p.Message{
Message: &p2p.Message_Handshake{
Handshake: &p2p.Handshake{
NetworkId: uint32(1337),
MyTime: uint64(time.Now().Unix()),
IpAddr: []byte(net.IPv4(1, 2, 3, 4).To16()),
IpPort: 0,
IpSigningTime: uint64(time.Now().Unix()),
IpNodeIdSig: []byte{'y', 'e', 'e', 't'},
TrackedNets: [][]byte{id[:]},
IpBlsSig: []byte{'y', 'e', 'e', 't', '2'},
},
},
}
msgLen := p2p.Size(&msg)
useBuilder := os.Getenv("USE_BUILDER") != ""
codec, err := newMsgBuilder(metric.NewRegistry(), 10*time.Second)
require.NoError(err)
b.Logf("proto length %d-byte (use builder %v)", msgLen, useBuilder)
b.ResetTimer()
for i := 0; i < b.N; i++ {
if useBuilder {
_, err = codec.createOutbound(&msg, compression.TypeNone, false)
} else {
_, err = p2p.Marshal(&msg)
}
require.NoError(err)
}
}
// Benchmarks unmarshal-ing "Version" message.
//
// e.g.,
//
// $ go install -v golang.org/x/tools/cmd/benchcmp@latest
// $ go install -v golang.org/x/perf/cmd/benchstat@latest
//
// $ go test -run=NONE -bench=BenchmarkUnmarshalHandshake > /tmp/cpu.before.txt
// $ USE_BUILDER=true go test -run=NONE -bench=BenchmarkUnmarshalHandshake > /tmp/cpu.after.txt
// $ benchcmp /tmp/cpu.before.txt /tmp/cpu.after.txt
// $ benchstat -alpha 0.03 -geomean /tmp/cpu.before.txt /tmp/cpu.after.txt
//
// $ go test -run=NONE -bench=BenchmarkUnmarshalHandshake -benchmem > /tmp/mem.before.txt
// $ USE_BUILDER=true go test -run=NONE -bench=BenchmarkUnmarshalHandshake -benchmem > /tmp/mem.after.txt
// $ benchcmp /tmp/mem.before.txt /tmp/mem.after.txt
// $ benchstat -alpha 0.03 -geomean /tmp/mem.before.txt /tmp/mem.after.txt
func BenchmarkUnmarshalHandshake(b *testing.B) {
require := require.New(b)
b.StopTimer()
id := ids.GenerateTestID()
msg := p2p.Message{
Message: &p2p.Message_Handshake{
Handshake: &p2p.Handshake{
NetworkId: uint32(1337),
MyTime: uint64(time.Now().Unix()),
IpAddr: []byte(net.IPv4(1, 2, 3, 4).To16()),
IpPort: 0,
IpSigningTime: uint64(time.Now().Unix()),
IpNodeIdSig: []byte{'y', 'e', 'e', 't'},
TrackedNets: [][]byte{id[:]},
IpBlsSig: []byte{'y', 'e', 'e', 't', '2'},
},
},
}
rawMsg, err := p2p.Marshal(&msg)
require.NoError(err)
useBuilder := os.Getenv("USE_BUILDER") != ""
codec, err := newMsgBuilder(metric.NewRegistry(), 10*time.Second)
require.NoError(err)
b.StartTimer()
for i := 0; i < b.N; i++ {
if useBuilder {
_, err = codec.parseInbound(rawMsg, dummyNodeID, dummyOnFinishedHandling)
require.NoError(err)
} else {
var msg p2p.Message
require.NoError(p2p.Unmarshal(rawMsg, &msg))
}
}
}
+755
View File
@@ -0,0 +1,755 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package message
import (
"bytes"
"github.com/luxfi/metric"
"net"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/luxfi/ids"
"github.com/luxfi/node/proto/p2p"
"github.com/luxfi/node/staking"
compression "github.com/luxfi/compress"
)
func TestMessage(t *testing.T) {
t.Parallel()
mb, err := newMsgBuilder(
metric.NewRegistry(),
5*time.Second,
)
require.NoError(t, err)
testID := ids.GenerateTestID()
compressibleContainers := [][]byte{
bytes.Repeat([]byte{0}, 100),
bytes.Repeat([]byte{0}, 32),
bytes.Repeat([]byte{0}, 32),
}
testCertRaw, testKeyRaw, err := staking.NewCertAndKeyBytes()
require.NoError(t, err)
testTLSCert, err := staking.LoadTLSCertFromBytes(testKeyRaw, testCertRaw)
require.NoError(t, err)
nowUnix := time.Now().Unix()
tests := []struct {
desc string
op Op
msg *p2p.Message
compressionType compression.Type
bypassThrottling bool
bytesSaved bool // if true, outbound message saved bytes must be non-zero
}{
{
desc: "ping message with no compression no uptime",
op: PingOp,
msg: &p2p.Message{
Message: &p2p.Message_Ping{
Ping: &p2p.Ping{},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
{
desc: "pong message with no compression",
op: PongOp,
msg: &p2p.Message{
Message: &p2p.Message_Pong{
Pong: &p2p.Pong{},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
{
desc: "ping message with no compression and uptime",
op: PingOp,
msg: &p2p.Message{
Message: &p2p.Message_Ping{
Ping: &p2p.Ping{
Uptime: 100,
},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
{
desc: "Handshake message with no compression",
op: HandshakeOp,
msg: &p2p.Message{
Message: &p2p.Message_Handshake{
Handshake: &p2p.Handshake{
NetworkId: uint32(1337),
MyTime: uint64(nowUnix),
IpAddr: []byte(net.IPv6zero),
IpPort: 9631,
IpSigningTime: uint64(nowUnix),
IpNodeIdSig: []byte{'y', 'e', 'e', 't'},
TrackedNets: [][]byte{testID[:]},
IpBlsSig: []byte{'y', 'e', 'e', 't', '2'},
},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
{
desc: "get_peer_list message with no compression",
op: GetPeerListOp,
msg: &p2p.Message{
Message: &p2p.Message_GetPeerList{
GetPeerList: &p2p.GetPeerList{
KnownPeers: &p2p.BloomFilter{
Filter: make([]byte, 2048),
Salt: make([]byte, 32),
},
},
},
},
compressionType: compression.TypeNone,
bypassThrottling: false,
bytesSaved: false,
},
{
desc: "get_peer_list message with zstd compression",
op: GetPeerListOp,
msg: &p2p.Message{
Message: &p2p.Message_GetPeerList{
GetPeerList: &p2p.GetPeerList{
KnownPeers: &p2p.BloomFilter{
Filter: make([]byte, 2048),
Salt: make([]byte, 32),
},
},
},
},
compressionType: compression.TypeZstd,
bypassThrottling: false,
bytesSaved: true,
},
{
desc: "peer_list message with no compression",
op: PeerListOp,
msg: &p2p.Message{
Message: &p2p.Message_PeerList_{
PeerList_: &p2p.PeerList{
ClaimedIpPorts: []*p2p.ClaimedIpPort{
{
X509Certificate: testTLSCert.Certificate[0],
IpAddr: []byte(net.IPv4zero),
IpPort: 10,
Timestamp: 1,
Signature: []byte{0},
},
},
},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
{
desc: "peer_list message with zstd compression",
op: PeerListOp,
msg: &p2p.Message{
Message: &p2p.Message_PeerList_{
PeerList_: &p2p.PeerList{
ClaimedIpPorts: []*p2p.ClaimedIpPort{
{
X509Certificate: testTLSCert.Certificate[0],
IpAddr: []byte(net.IPv6zero),
IpPort: 9631,
Timestamp: uint64(nowUnix),
Signature: compressibleContainers[0],
},
},
},
},
},
compressionType: compression.TypeZstd,
bypassThrottling: true,
bytesSaved: true,
},
{
desc: "get_state_summary_frontier message with no compression",
op: GetStateSummaryFrontierOp,
msg: &p2p.Message{
Message: &p2p.Message_GetStateSummaryFrontier{
GetStateSummaryFrontier: &p2p.GetStateSummaryFrontier{
ChainId: testID[:],
RequestId: 1,
Deadline: 1,
},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
{
desc: "state_summary_frontier message with no compression",
op: StateSummaryFrontierOp,
msg: &p2p.Message{
Message: &p2p.Message_StateSummaryFrontier_{
StateSummaryFrontier_: &p2p.StateSummaryFrontier{
ChainId: testID[:],
RequestId: 1,
Summary: []byte{0},
},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
{
desc: "state_summary_frontier message with zstd compression",
op: StateSummaryFrontierOp,
msg: &p2p.Message{
Message: &p2p.Message_StateSummaryFrontier_{
StateSummaryFrontier_: &p2p.StateSummaryFrontier{
ChainId: testID[:],
RequestId: 1,
Summary: compressibleContainers[0],
},
},
},
compressionType: compression.TypeZstd,
bypassThrottling: true,
bytesSaved: true,
},
{
desc: "get_accepted_state_summary message with no compression",
op: GetAcceptedStateSummaryOp,
msg: &p2p.Message{
Message: &p2p.Message_GetAcceptedStateSummary{
GetAcceptedStateSummary: &p2p.GetAcceptedStateSummary{
ChainId: testID[:],
RequestId: 1,
Deadline: 1,
Heights: []uint64{0},
},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
{
desc: "get_accepted_state_summary message with zstd compression",
op: GetAcceptedStateSummaryOp,
msg: &p2p.Message{
Message: &p2p.Message_GetAcceptedStateSummary{
GetAcceptedStateSummary: &p2p.GetAcceptedStateSummary{
ChainId: testID[:],
RequestId: 1,
Deadline: 1,
Heights: []uint64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
},
},
},
compressionType: compression.TypeZstd,
bypassThrottling: true,
bytesSaved: false, // Small data may not benefit from compression
},
{
desc: "accepted_state_summary message with no compression",
op: AcceptedStateSummaryOp,
msg: &p2p.Message{
Message: &p2p.Message_AcceptedStateSummary_{
AcceptedStateSummary_: &p2p.AcceptedStateSummary{
ChainId: testID[:],
RequestId: 1,
SummaryIds: [][]byte{testID[:], testID[:]},
},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
{
desc: "accepted_state_summary message with zstd compression",
op: AcceptedStateSummaryOp,
msg: &p2p.Message{
Message: &p2p.Message_AcceptedStateSummary_{
AcceptedStateSummary_: &p2p.AcceptedStateSummary{
ChainId: testID[:],
RequestId: 1,
SummaryIds: [][]byte{testID[:], testID[:], testID[:], testID[:], testID[:], testID[:], testID[:], testID[:], testID[:]},
},
},
},
compressionType: compression.TypeZstd,
bypassThrottling: true,
bytesSaved: true,
},
{
desc: "get_accepted_frontier message with no compression",
op: GetAcceptedFrontierOp,
msg: &p2p.Message{
Message: &p2p.Message_GetAcceptedFrontier{
GetAcceptedFrontier: &p2p.GetAcceptedFrontier{
ChainId: testID[:],
RequestId: 1,
Deadline: 1,
},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
{
desc: "accepted_frontier message with no compression",
op: AcceptedFrontierOp,
msg: &p2p.Message{
Message: &p2p.Message_AcceptedFrontier_{
AcceptedFrontier_: &p2p.AcceptedFrontier{
ChainId: testID[:],
RequestId: 1,
ContainerId: testID[:],
},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
{
desc: "get_accepted message with no compression",
op: GetAcceptedOp,
msg: &p2p.Message{
Message: &p2p.Message_GetAccepted{
GetAccepted: &p2p.GetAccepted{
ChainId: testID[:],
RequestId: 1,
Deadline: 1,
ContainerIds: [][]byte{testID[:], testID[:]},
},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
{
desc: "accepted message with no compression",
op: AcceptedOp,
msg: &p2p.Message{
Message: &p2p.Message_Accepted_{
Accepted_: &p2p.Accepted{
ChainId: testID[:],
RequestId: 1,
ContainerIds: [][]byte{testID[:], testID[:]},
},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
{
desc: "get_ancestors message with no compression",
op: GetAncestorsOp,
msg: &p2p.Message{
Message: &p2p.Message_GetAncestors{
GetAncestors: &p2p.GetAncestors{
ChainId: testID[:],
RequestId: 1,
Deadline: 1,
ContainerId: testID[:],
EngineType: p2p.EngineType_ENGINE_TYPE_DAG,
},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
{
desc: "ancestors message with no compression",
op: AncestorsOp,
msg: &p2p.Message{
Message: &p2p.Message_Ancestors_{
Ancestors_: &p2p.Ancestors{
ChainId: testID[:],
RequestId: 12345,
Containers: compressibleContainers,
},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
{
desc: "ancestors message with zstd compression",
op: AncestorsOp,
msg: &p2p.Message{
Message: &p2p.Message_Ancestors_{
Ancestors_: &p2p.Ancestors{
ChainId: testID[:],
RequestId: 12345,
Containers: compressibleContainers,
},
},
},
compressionType: compression.TypeZstd,
bypassThrottling: true,
bytesSaved: true,
},
{
desc: "get message with no compression",
op: GetOp,
msg: &p2p.Message{
Message: &p2p.Message_Get{
Get: &p2p.Get{
ChainId: testID[:],
RequestId: 1,
Deadline: 1,
ContainerId: testID[:],
},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
{
desc: "put message with no compression",
op: PutOp,
msg: &p2p.Message{
Message: &p2p.Message_Put{
Put: &p2p.Put{
ChainId: testID[:],
RequestId: 1,
Container: []byte{0},
},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
{
desc: "put message with zstd compression",
op: PutOp,
msg: &p2p.Message{
Message: &p2p.Message_Put{
Put: &p2p.Put{
ChainId: testID[:],
RequestId: 1,
Container: compressibleContainers[0],
},
},
},
compressionType: compression.TypeZstd,
bypassThrottling: true,
bytesSaved: true,
},
{
desc: "push_query message with no compression",
op: PushQueryOp,
msg: &p2p.Message{
Message: &p2p.Message_PushQuery{
PushQuery: &p2p.PushQuery{
ChainId: testID[:],
RequestId: 1,
Deadline: 1,
Container: []byte{0},
},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
{
desc: "push_query message with zstd compression",
op: PushQueryOp,
msg: &p2p.Message{
Message: &p2p.Message_PushQuery{
PushQuery: &p2p.PushQuery{
ChainId: testID[:],
RequestId: 1,
Deadline: 1,
Container: compressibleContainers[0],
},
},
},
compressionType: compression.TypeZstd,
bypassThrottling: true,
bytesSaved: true,
},
{
desc: "pull_query message with no compression",
op: PullQueryOp,
msg: &p2p.Message{
Message: &p2p.Message_PullQuery{
PullQuery: &p2p.PullQuery{
ChainId: testID[:],
RequestId: 1,
Deadline: 1,
ContainerId: testID[:],
},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
{
desc: "qbit message with no compression",
op: QbitOp,
msg: &p2p.Message{
Message: &p2p.Message_Chits{
Chits: &p2p.Chits{
ChainId: testID[:],
RequestId: 1,
PreferredId: testID[:],
},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
{
desc: "app_request message with no compression",
op: RequestOp,
msg: &p2p.Message{
Message: &p2p.Message_Request{
Request: &p2p.Request{
ChainId: testID[:],
RequestId: 1,
Deadline: 1,
AppBytes: compressibleContainers[0],
},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
{
desc: "app_request message with zstd compression",
op: RequestOp,
msg: &p2p.Message{
Message: &p2p.Message_Request{
Request: &p2p.Request{
ChainId: testID[:],
RequestId: 1,
Deadline: 1,
AppBytes: compressibleContainers[0],
},
},
},
compressionType: compression.TypeZstd,
bypassThrottling: true,
bytesSaved: true,
},
{
desc: "app_response message with no compression",
op: ResponseOp,
msg: &p2p.Message{
Message: &p2p.Message_Response{
Response: &p2p.Response{
ChainId: testID[:],
RequestId: 1,
AppBytes: compressibleContainers[0],
},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
{
desc: "app_response message with zstd compression",
op: ResponseOp,
msg: &p2p.Message{
Message: &p2p.Message_Response{
Response: &p2p.Response{
ChainId: testID[:],
RequestId: 1,
AppBytes: compressibleContainers[0],
},
},
},
compressionType: compression.TypeZstd,
bypassThrottling: true,
bytesSaved: true,
},
{
desc: "app_gossip message with no compression",
op: GossipOp,
msg: &p2p.Message{
Message: &p2p.Message_Gossip{
Gossip: &p2p.Gossip{
ChainId: testID[:],
AppBytes: compressibleContainers[0],
},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
{
desc: "app_gossip message with zstd compression",
op: GossipOp,
msg: &p2p.Message{
Message: &p2p.Message_Gossip{
Gossip: &p2p.Gossip{
ChainId: testID[:],
AppBytes: compressibleContainers[0],
},
},
},
compressionType: compression.TypeZstd,
bypassThrottling: true,
bytesSaved: true,
},
{
desc: "bft message with no compression",
op: BFTOp,
msg: &p2p.Message{
Message: &p2p.Message_BFT{
BFT: &p2p.BFT{
ChainId: testID[:],
Message: &p2p.BFT_ReplicationRequest{
ReplicationRequest: &p2p.ReplicationRequest{
Seqs: []uint64{1, 2, 3},
LatestRound: 1,
},
},
},
},
},
compressionType: compression.TypeNone,
bypassThrottling: true,
bytesSaved: false,
},
}
for _, tv := range tests {
t.Run(tv.desc, func(t *testing.T) {
require := require.New(t)
encodedMsg, err := mb.createOutbound(tv.msg, tv.compressionType, tv.bypassThrottling)
require.NoError(err)
require.Equal(tv.bypassThrottling, encodedMsg.BypassThrottling())
require.Equal(tv.op, encodedMsg.Op())
if bytesSaved := encodedMsg.BytesSavedCompression(); tv.bytesSaved {
require.Positive(bytesSaved)
}
parsedMsg, err := mb.parseInbound(encodedMsg.Bytes(), ids.EmptyNodeID, func() {})
require.NoError(err)
require.Equal(tv.op, parsedMsg.Op())
})
}
}
// Tests the Stringer interface on inbound messages
func TestInboundMessageToString(t *testing.T) {
t.Parallel()
require := require.New(t)
mb, err := newMsgBuilder(
metric.NewRegistry(),
5*time.Second,
)
require.NoError(err)
// msg that will become the tested InboundMessage
msg := &p2p.Message{
Message: &p2p.Message_Pong{
Pong: &p2p.Pong{},
},
}
msgBytes, err := p2p.Marshal(msg)
require.NoError(err)
inboundMsg, err := mb.parseInbound(msgBytes, ids.EmptyNodeID, func() {})
require.NoError(err)
// ZAP returns "Pong{Uptime:0}", proto returns empty string
require.Contains(inboundMsg.String(), "NodeID-111111111111111111116DBWJs Op: pong Message:")
internalMsg := InternalGetStateSummaryFrontierFailed(ids.EmptyNodeID, ids.Empty, 1)
require.Equal("NodeID-111111111111111111116DBWJs Op: get_state_summary_frontier_failed Message: ChainID: 11111111111111111111111111111111LpoYY RequestID: 1", internalMsg.String())
}
func TestEmptyInboundMessage(t *testing.T) {
t.Parallel()
require := require.New(t)
mb, err := newMsgBuilder(
metric.NewRegistry(),
5*time.Second,
)
require.NoError(err)
msg := &p2p.Message{}
msgBytes, err := p2p.Marshal(msg)
// ZAP returns error at marshal time for empty message
if err != nil {
return
}
_, err = mb.parseInbound(msgBytes, ids.EmptyNodeID, func() {})
require.ErrorIs(err, errUnknownMessageType)
}
func TestNilInboundMessage(t *testing.T) {
t.Parallel()
require := require.New(t)
mb, err := newMsgBuilder(
metric.NewRegistry(),
5*time.Second,
)
require.NoError(err)
msg := &p2p.Message{
Message: &p2p.Message_Ping{
Ping: nil,
},
}
msgBytes, err := p2p.Marshal(msg)
// ZAP returns error at marshal time for nil message content
if err != nil {
return
}
parsedMsg, err := mb.parseInbound(msgBytes, ids.EmptyNodeID, func() {})
require.NoError(err)
require.IsType(&p2p.Ping{}, parsedMsg.message)
pingMsg := parsedMsg.message.(*p2p.Ping)
require.NotNil(pingMsg)
}
+95
View File
@@ -0,0 +1,95 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/luxfi/node/message (interfaces: OutboundMessage)
//
// Generated by this command:
//
// mockgen -package=message -destination=message/mock_message.go github.com/luxfi/node/message OutboundMessage
//
// Package message is a generated GoMock package.
package message
import (
reflect "reflect"
gomock "github.com/luxfi/mock/gomock"
)
// MockOutboundMessage is a mock of OutboundMessage interface.
type MockOutboundMessage struct {
ctrl *gomock.Controller
recorder *MockOutboundMessageMockRecorder
}
// MockOutboundMessageMockRecorder is the mock recorder for MockOutboundMessage.
type MockOutboundMessageMockRecorder struct {
mock *MockOutboundMessage
}
// NewMockOutboundMessage creates a new mock instance.
func NewMockOutboundMessage(ctrl *gomock.Controller) *MockOutboundMessage {
mock := &MockOutboundMessage{ctrl: ctrl}
mock.recorder = &MockOutboundMessageMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockOutboundMessage) EXPECT() *MockOutboundMessageMockRecorder {
return m.recorder
}
// BypassThrottling mocks base method.
func (m *MockOutboundMessage) BypassThrottling() bool {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BypassThrottling")
ret0, _ := ret[0].(bool)
return ret0
}
// BypassThrottling indicates an expected call of BypassThrottling.
func (mr *MockOutboundMessageMockRecorder) BypassThrottling() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BypassThrottling", reflect.TypeOf((*MockOutboundMessage)(nil).BypassThrottling))
}
// Bytes mocks base method.
func (m *MockOutboundMessage) Bytes() []byte {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Bytes")
ret0, _ := ret[0].([]byte)
return ret0
}
// Bytes indicates an expected call of Bytes.
func (mr *MockOutboundMessageMockRecorder) Bytes() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Bytes", reflect.TypeOf((*MockOutboundMessage)(nil).Bytes))
}
// BytesSavedCompression mocks base method.
func (m *MockOutboundMessage) BytesSavedCompression() int {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BytesSavedCompression")
ret0, _ := ret[0].(int)
return ret0
}
// BytesSavedCompression indicates an expected call of BytesSavedCompression.
func (mr *MockOutboundMessageMockRecorder) BytesSavedCompression() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BytesSavedCompression", reflect.TypeOf((*MockOutboundMessage)(nil).BytesSavedCompression))
}
// Op mocks base method.
func (m *MockOutboundMessage) Op() Op {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Op")
ret0, _ := ret[0].(Op)
return ret0
}
// Op indicates an expected call of Op.
func (mr *MockOutboundMessageMockRecorder) Op() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Op", reflect.TypeOf((*MockOutboundMessage)(nil).Op))
}
+405
View File
@@ -0,0 +1,405 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/luxfi/node/message (interfaces: OutboundMsgBuilder)
//
// Generated by this command:
//
// mockgen -package=message -destination=message/mock_outbound_message_builder.go github.com/luxfi/node/message OutboundMsgBuilder
//
// Package message is a generated GoMock package.
package message
import (
"go.uber.org/mock/gomock"
netip "net/netip"
reflect "reflect"
time "time"
ids "github.com/luxfi/ids"
p2p "github.com/luxfi/node/proto/p2p"
"github.com/luxfi/net/endpoints"
)
// MockOutboundMsgBuilder is a mock of OutboundMsgBuilder interface.
type MockOutboundMsgBuilder struct {
ctrl *gomock.Controller
recorder *MockOutboundMsgBuilderMockRecorder
}
// MockOutboundMsgBuilderMockRecorder is the mock recorder for MockOutboundMsgBuilder.
type MockOutboundMsgBuilderMockRecorder struct {
mock *MockOutboundMsgBuilder
}
// NewMockOutboundMsgBuilder creates a new mock instance.
func NewMockOutboundMsgBuilder(ctrl *gomock.Controller) *MockOutboundMsgBuilder {
mock := &MockOutboundMsgBuilder{ctrl: ctrl}
mock.recorder = &MockOutboundMsgBuilderMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockOutboundMsgBuilder) EXPECT() *MockOutboundMsgBuilderMockRecorder {
return m.recorder
}
// Accepted mocks base method.
func (m *MockOutboundMsgBuilder) Accepted(arg0 ids.ID, arg1 uint32, arg2 []ids.ID) (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Accepted", arg0, arg1, arg2)
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Accepted indicates an expected call of Accepted.
func (mr *MockOutboundMsgBuilderMockRecorder) Accepted(arg0, arg1, arg2 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Accepted", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).Accepted), arg0, arg1, arg2)
}
// AcceptedFrontier mocks base method.
func (m *MockOutboundMsgBuilder) AcceptedFrontier(arg0 ids.ID, arg1 uint32, arg2 ids.ID) (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AcceptedFrontier", arg0, arg1, arg2)
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AcceptedFrontier indicates an expected call of AcceptedFrontier.
func (mr *MockOutboundMsgBuilderMockRecorder) AcceptedFrontier(arg0, arg1, arg2 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AcceptedFrontier", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).AcceptedFrontier), arg0, arg1, arg2)
}
// AcceptedStateSummary mocks base method.
func (m *MockOutboundMsgBuilder) AcceptedStateSummary(arg0 ids.ID, arg1 uint32, arg2 []ids.ID) (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AcceptedStateSummary", arg0, arg1, arg2)
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AcceptedStateSummary indicates an expected call of AcceptedStateSummary.
func (mr *MockOutboundMsgBuilderMockRecorder) AcceptedStateSummary(arg0, arg1, arg2 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AcceptedStateSummary", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).AcceptedStateSummary), arg0, arg1, arg2)
}
// Ancestors mocks base method.
func (m *MockOutboundMsgBuilder) Ancestors(arg0 ids.ID, arg1 uint32, arg2 [][]byte) (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Ancestors", arg0, arg1, arg2)
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Ancestors indicates an expected call of Ancestors.
func (mr *MockOutboundMsgBuilderMockRecorder) Ancestors(arg0, arg1, arg2 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ancestors", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).Ancestors), arg0, arg1, arg2)
}
// Error mocks base method.
func (m *MockOutboundMsgBuilder) Error(arg0 ids.ID, arg1 uint32, arg2 int32, arg3 string) (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Error", arg0, arg1, arg2, arg3)
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Error indicates an expected call of Error.
func (mr *MockOutboundMsgBuilderMockRecorder) Error(arg0, arg1, arg2, arg3 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).Error), arg0, arg1, arg2, arg3)
}
// Gossip mocks base method.
func (m *MockOutboundMsgBuilder) Gossip(arg0 ids.ID, arg1 []byte) (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Gossip", arg0, arg1)
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Gossip indicates an expected call of Gossip.
func (mr *MockOutboundMsgBuilderMockRecorder) Gossip(arg0, arg1 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Gossip", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).Gossip), arg0, arg1)
}
// Request mocks base method.
func (m *MockOutboundMsgBuilder) Request(arg0 ids.ID, arg1 uint32, arg2 time.Duration, arg3 []byte) (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Request", arg0, arg1, arg2, arg3)
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Request indicates an expected call of Request.
func (mr *MockOutboundMsgBuilderMockRecorder) Request(arg0, arg1, arg2, arg3 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Request", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).Request), arg0, arg1, arg2, arg3)
}
// Response mocks base method.
func (m *MockOutboundMsgBuilder) Response(arg0 ids.ID, arg1 uint32, arg2 []byte) (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Response", arg0, arg1, arg2)
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Response indicates an expected call of Response.
func (mr *MockOutboundMsgBuilderMockRecorder) Response(arg0, arg1, arg2 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Response", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).Response), arg0, arg1, arg2)
}
// Chits mocks base method.
func (m *MockOutboundMsgBuilder) Chits(arg0 ids.ID, arg1 uint32, arg2, arg3, arg4 ids.ID) (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Chits", arg0, arg1, arg2, arg3, arg4)
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Chits indicates an expected call of Chits.
func (mr *MockOutboundMsgBuilderMockRecorder) Chits(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Chits", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).Chits), arg0, arg1, arg2, arg3, arg4)
}
// Get mocks base method.
func (m *MockOutboundMsgBuilder) Get(arg0 ids.ID, arg1 uint32, arg2 time.Duration, arg3 ids.ID) (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Get", arg0, arg1, arg2, arg3)
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Get indicates an expected call of Get.
func (mr *MockOutboundMsgBuilderMockRecorder) Get(arg0, arg1, arg2, arg3 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).Get), arg0, arg1, arg2, arg3)
}
// GetAccepted mocks base method.
func (m *MockOutboundMsgBuilder) GetAccepted(arg0 ids.ID, arg1 uint32, arg2 time.Duration, arg3 []ids.ID) (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetAccepted", arg0, arg1, arg2, arg3)
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetAccepted indicates an expected call of GetAccepted.
func (mr *MockOutboundMsgBuilderMockRecorder) GetAccepted(arg0, arg1, arg2, arg3 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccepted", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).GetAccepted), arg0, arg1, arg2, arg3)
}
// GetAcceptedFrontier mocks base method.
func (m *MockOutboundMsgBuilder) GetAcceptedFrontier(arg0 ids.ID, arg1 uint32, arg2 time.Duration) (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetAcceptedFrontier", arg0, arg1, arg2)
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetAcceptedFrontier indicates an expected call of GetAcceptedFrontier.
func (mr *MockOutboundMsgBuilderMockRecorder) GetAcceptedFrontier(arg0, arg1, arg2 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAcceptedFrontier", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).GetAcceptedFrontier), arg0, arg1, arg2)
}
// GetAcceptedStateSummary mocks base method.
func (m *MockOutboundMsgBuilder) GetAcceptedStateSummary(arg0 ids.ID, arg1 uint32, arg2 time.Duration, arg3 []uint64) (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetAcceptedStateSummary", arg0, arg1, arg2, arg3)
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetAcceptedStateSummary indicates an expected call of GetAcceptedStateSummary.
func (mr *MockOutboundMsgBuilderMockRecorder) GetAcceptedStateSummary(arg0, arg1, arg2, arg3 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAcceptedStateSummary", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).GetAcceptedStateSummary), arg0, arg1, arg2, arg3)
}
// GetAncestors mocks base method.
func (m *MockOutboundMsgBuilder) GetAncestors(arg0 ids.ID, arg1 uint32, arg2 time.Duration, arg3 ids.ID, arg4 p2p.EngineType) (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetAncestors", arg0, arg1, arg2, arg3, arg4)
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetAncestors indicates an expected call of GetAncestors.
func (mr *MockOutboundMsgBuilderMockRecorder) GetAncestors(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAncestors", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).GetAncestors), arg0, arg1, arg2, arg3, arg4)
}
// GetPeerList mocks base method.
func (m *MockOutboundMsgBuilder) GetPeerList(arg0, arg1 []byte) (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetPeerList", arg0, arg1)
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetPeerList indicates an expected call of GetPeerList.
func (mr *MockOutboundMsgBuilderMockRecorder) GetPeerList(arg0, arg1 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPeerList", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).GetPeerList), arg0, arg1)
}
// GetStateSummaryFrontier mocks base method.
func (m *MockOutboundMsgBuilder) GetStateSummaryFrontier(arg0 ids.ID, arg1 uint32, arg2 time.Duration) (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetStateSummaryFrontier", arg0, arg1, arg2)
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetStateSummaryFrontier indicates an expected call of GetStateSummaryFrontier.
func (mr *MockOutboundMsgBuilderMockRecorder) GetStateSummaryFrontier(arg0, arg1, arg2 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStateSummaryFrontier", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).GetStateSummaryFrontier), arg0, arg1, arg2)
}
// Handshake mocks base method.
func (m *MockOutboundMsgBuilder) Handshake(arg0 uint32, arg1 uint64, arg2 netip.AddrPort, arg3 string, arg4, arg5, arg6 uint32, arg7 uint64, arg8, arg9 []byte, arg10 []ids.ID, arg11, arg12 []uint32, arg13, arg14 []byte) (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Handshake", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14)
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Handshake indicates an expected call of Handshake.
func (mr *MockOutboundMsgBuilderMockRecorder) Handshake(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Handshake", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).Handshake), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14)
}
// PeerList mocks base method.
func (m *MockOutboundMsgBuilder) PeerList(arg0 []*endpoints.ClaimedIPPort, arg1 bool) (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PeerList", arg0, arg1)
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// PeerList indicates an expected call of PeerList.
func (mr *MockOutboundMsgBuilderMockRecorder) PeerList(arg0, arg1 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PeerList", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).PeerList), arg0, arg1)
}
// Ping mocks base method.
func (m *MockOutboundMsgBuilder) Ping(arg0 uint32) (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Ping", arg0)
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Ping indicates an expected call of Ping.
func (mr *MockOutboundMsgBuilderMockRecorder) Ping(arg0, arg1 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ping", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).Ping), arg0, arg1)
}
// Pong mocks base method.
func (m *MockOutboundMsgBuilder) Pong() (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Pong")
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Pong indicates an expected call of Pong.
func (mr *MockOutboundMsgBuilderMockRecorder) Pong() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Pong", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).Pong))
}
// PullQuery mocks base method.
func (m *MockOutboundMsgBuilder) PullQuery(arg0 ids.ID, arg1 uint32, arg2 time.Duration, arg3 ids.ID, arg4 uint64) (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PullQuery", arg0, arg1, arg2, arg3, arg4)
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// PullQuery indicates an expected call of PullQuery.
func (mr *MockOutboundMsgBuilderMockRecorder) PullQuery(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PullQuery", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).PullQuery), arg0, arg1, arg2, arg3, arg4)
}
// PushQuery mocks base method.
func (m *MockOutboundMsgBuilder) PushQuery(arg0 ids.ID, arg1 uint32, arg2 time.Duration, arg3 []byte, arg4 uint64) (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PushQuery", arg0, arg1, arg2, arg3, arg4)
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// PushQuery indicates an expected call of PushQuery.
func (mr *MockOutboundMsgBuilderMockRecorder) PushQuery(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PushQuery", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).PushQuery), arg0, arg1, arg2, arg3, arg4)
}
// Put mocks base method.
func (m *MockOutboundMsgBuilder) Put(arg0 ids.ID, arg1 uint32, arg2 []byte) (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Put", arg0, arg1, arg2)
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Put indicates an expected call of Put.
func (mr *MockOutboundMsgBuilderMockRecorder) Put(arg0, arg1, arg2 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).Put), arg0, arg1, arg2)
}
// StateSummaryFrontier mocks base method.
func (m *MockOutboundMsgBuilder) StateSummaryFrontier(arg0 ids.ID, arg1 uint32, arg2 []byte) (OutboundMessage, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "StateSummaryFrontier", arg0, arg1, arg2)
ret0, _ := ret[0].(OutboundMessage)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// StateSummaryFrontier indicates an expected call of StateSummaryFrontier.
func (mr *MockOutboundMsgBuilderMockRecorder) StateSummaryFrontier(arg0, arg1, arg2 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateSummaryFrontier", reflect.TypeOf((*MockOutboundMsgBuilder)(nil).StateSummaryFrontier), arg0, arg1, arg2)
}
+7
View File
@@ -0,0 +1,7 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package message
//go:generate go run go.uber.org/mock/mockgen -package=${GOPACKAGE}mock -destination=${GOPACKAGE}mock/outbound_message.go -mock_names=OutboundMessage=OutboundMessage . OutboundMessage
//go:generate go run go.uber.org/mock/mockgen -package=${GOPACKAGE}mock -destination=${GOPACKAGE}mock/outbound_message_builder.go -mock_names=OutboundMsgBuilder=OutboundMsgBuilder . OutboundMsgBuilder
+403
View File
@@ -0,0 +1,403 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package message
import (
"encoding/binary"
"errors"
"fmt"
"github.com/luxfi/math/set"
"github.com/luxfi/node/proto/p2p"
)
// Op is an opcode
type Op byte
// Types of messages that may be sent between nodes
// Note: If you add a new parseable Op below, you must add it to either
// [UnrequestedOps] or [FailedToResponseOps].
const (
// Handshake:
PingOp Op = iota
PongOp
HandshakeOp
GetPeerListOp
PeerListOp
// State sync:
GetStateSummaryFrontierOp
GetStateSummaryFrontierFailedOp
StateSummaryFrontierOp
GetAcceptedStateSummaryOp
GetAcceptedStateSummaryFailedOp
AcceptedStateSummaryOp
// Bootstrapping:
GetAcceptedFrontierOp
GetAcceptedFrontierFailedOp
AcceptedFrontierOp
GetAcceptedOp
GetAcceptedFailedOp
AcceptedOp
GetAncestorsOp
GetAncestorsFailedOp
AncestorsOp
// Consensus:
GetOp
GetFailedOp
PutOp
PushQueryOp
PullQueryOp
QueryFailedOp
QbitOp // Authenticated preference signal (formerly ChitsOp)
// Application:
RequestOp
ErrorOp
ResponseOp
GossipOp
// Internal:
ConnectedOp
DisconnectedOp
NotifyOp
GossipRequestOp
// BFT
BFTOp
)
var (
// UnrequestedOps are operations that are expected to be seen without having
// requested them. For example, a peer may receive a Get request for a block
// without having sent a message previously.
UnrequestedOps = set.Of(
GetAcceptedFrontierOp,
GetAcceptedOp,
GetAncestorsOp,
GetOp,
PushQueryOp,
PullQueryOp,
RequestOp,
GossipOp,
GetStateSummaryFrontierOp,
GetAcceptedStateSummaryOp,
BFTOp,
)
// FailedToResponseOps maps response failure messages to their successful
// counterparts.
FailedToResponseOps = map[Op]Op{
GetStateSummaryFrontierFailedOp: StateSummaryFrontierOp,
GetAcceptedStateSummaryFailedOp: AcceptedStateSummaryOp,
GetAcceptedFrontierFailedOp: AcceptedFrontierOp,
GetAcceptedFailedOp: AcceptedOp,
GetAncestorsFailedOp: AncestorsOp,
GetFailedOp: PutOp,
QueryFailedOp: QbitOp,
ErrorOp: ResponseOp,
}
errUnknownMessageType = errors.New("unknown message type")
)
func (op Op) String() string {
switch op {
// Handshake
case PingOp:
return "ping"
case PongOp:
return "pong"
case HandshakeOp:
return "handshake"
case GetPeerListOp:
return "get_peerlist"
case PeerListOp:
return "peerlist"
// State sync
case GetStateSummaryFrontierOp:
return "get_state_summary_frontier"
case GetStateSummaryFrontierFailedOp:
return "get_state_summary_frontier_failed"
case StateSummaryFrontierOp:
return "state_summary_frontier"
case GetAcceptedStateSummaryOp:
return "get_accepted_state_summary"
case GetAcceptedStateSummaryFailedOp:
return "get_accepted_state_summary_failed"
case AcceptedStateSummaryOp:
return "accepted_state_summary"
// Bootstrapping
case GetAcceptedFrontierOp:
return "get_accepted_frontier"
case GetAcceptedFrontierFailedOp:
return "get_accepted_frontier_failed"
case AcceptedFrontierOp:
return "accepted_frontier"
case GetAcceptedOp:
return "get_accepted"
case GetAcceptedFailedOp:
return "get_accepted_failed"
case AcceptedOp:
return "accepted"
case GetAncestorsOp:
return "get_ancestors"
case GetAncestorsFailedOp:
return "get_ancestors_failed"
case AncestorsOp:
return "ancestors"
// Consensus
case GetOp:
return "get"
case GetFailedOp:
return "get_failed"
case PutOp:
return "put"
case PushQueryOp:
return "push_query"
case PullQueryOp:
return "pull_query"
case QueryFailedOp:
return "query_failed"
case QbitOp:
return "qbit"
// Application
case RequestOp:
return "app_request"
case ErrorOp:
return "app_error"
case ResponseOp:
return "app_response"
case GossipOp:
return "app_gossip"
// Internal
case ConnectedOp:
return "connected"
case DisconnectedOp:
return "disconnected"
case NotifyOp:
return "notify"
case GossipRequestOp:
return "gossip_request"
// BFT
case BFTOp:
return "bft"
default:
return "unknown"
}
}
func Unwrap(m *p2p.Message) (fmt.Stringer, error) {
switch msg := m.GetMessage().(type) {
// Handshake:
case *p2p.Message_Ping:
return msg.Ping, nil
case *p2p.Message_Pong:
return msg.Pong, nil
case *p2p.Message_Handshake:
return msg.Handshake, nil
case *p2p.Message_GetPeerList:
return msg.GetPeerList, nil
case *p2p.Message_PeerList_:
return msg.PeerList_, nil
// State sync:
case *p2p.Message_GetStateSummaryFrontier:
return msg.GetStateSummaryFrontier, nil
case *p2p.Message_StateSummaryFrontier_:
return msg.StateSummaryFrontier_, nil
case *p2p.Message_GetAcceptedStateSummary:
return msg.GetAcceptedStateSummary, nil
case *p2p.Message_AcceptedStateSummary_:
return msg.AcceptedStateSummary_, nil
// Bootstrapping:
case *p2p.Message_GetAcceptedFrontier:
return msg.GetAcceptedFrontier, nil
case *p2p.Message_AcceptedFrontier_:
return msg.AcceptedFrontier_, nil
case *p2p.Message_GetAccepted:
return msg.GetAccepted, nil
case *p2p.Message_Accepted_:
return msg.Accepted_, nil
case *p2p.Message_GetAncestors:
return msg.GetAncestors, nil
case *p2p.Message_Ancestors_:
return msg.Ancestors_, nil
// Consensus:
case *p2p.Message_Get:
return msg.Get, nil
case *p2p.Message_Put:
return msg.Put, nil
case *p2p.Message_PushQuery:
return msg.PushQuery, nil
case *p2p.Message_PullQuery:
return msg.PullQuery, nil
case *p2p.Message_Chits:
return msg.Chits, nil
// Application:
case *p2p.Message_Request:
return msg.Request, nil
case *p2p.Message_Response:
return msg.Response, nil
case *p2p.Message_Error:
return msg.Error, nil
case *p2p.Message_Gossip:
return msg.Gossip, nil
// BFT
case *p2p.Message_BFT:
return extractBFT(msg), nil
default:
return nil, fmt.Errorf("%w: %T", errUnknownMessageType, msg)
}
}
// ToConsensusOp maps message.Op to consensus router Op values
// Returns the consensus Op value and whether the mapping exists
func ToConsensusOp(op Op) (byte, bool) {
switch op {
case GetAcceptedFrontierOp:
return 0, true // GetAcceptedFrontier
case AcceptedFrontierOp:
return 1, true // AcceptedFrontier
case GetAcceptedOp:
return 2, true // GetAccepted
case AcceptedOp:
return 3, true // Accepted
case GetOp:
return 4, true // Get
case PutOp:
return 5, true // Put
case PushQueryOp:
return 6, true // PushQuery
case PullQueryOp:
return 7, true // PullQuery
case QbitOp:
return 8, true // Qbit
case GetAncestorsOp:
return 9, true // GetContext (wire protocol still uses GetAncestors)
case AncestorsOp:
return 10, true // Context (wire protocol still uses Ancestors)
default:
return 0, false
}
}
// GetContainerBytes extracts the container/body bytes from various message types
func GetContainerBytes(msg fmt.Stringer) []byte {
switch m := msg.(type) {
case *p2p.Put:
return m.Container
case *p2p.PushQuery:
return m.Container
case *p2p.Ancestors:
// Encode all containers with length prefix so handlers can decode
// multiple blocks from a single byte slice.
if len(m.Containers) == 0 {
return nil
}
totalLen := 0
for _, container := range m.Containers {
totalLen += 4 + len(container)
}
encoded := make([]byte, 0, totalLen)
for _, container := range m.Containers {
var lenBuf [4]byte
binary.BigEndian.PutUint32(lenBuf[:], uint32(len(container)))
encoded = append(encoded, lenBuf[:]...)
encoded = append(encoded, container...)
}
return encoded
case *p2p.Gossip:
return m.AppBytes
case *p2p.Request:
return m.AppBytes
case *p2p.Response:
return m.AppBytes
// Request messages with container IDs for P-Chain sync
case *p2p.GetAccepted:
containerIDs := m.GetContainerIds()
if len(containerIDs) == 0 {
return nil
}
result := make([]byte, 0, len(containerIDs)*32)
for _, id := range containerIDs {
result = append(result, id...)
}
return result
case *p2p.Get:
return m.GetContainerId()
case *p2p.GetAncestors:
return m.GetContainerId()
case *p2p.PullQuery:
return m.GetContainerId()
case *p2p.Chits:
// For Qbit messages (formerly Chits), return the PreferredId (the block being voted for)
return m.GetPreferredId()
case *p2p.AcceptedFrontier:
return m.GetContainerId()
case *p2p.Accepted:
containerIDs := m.GetContainerIds()
if len(containerIDs) == 0 {
return nil
}
result := make([]byte, 0, len(containerIDs)*32)
for _, id := range containerIDs {
result = append(result, id...)
}
return result
default:
return nil
}
}
func ToOp(m *p2p.Message) (Op, error) {
switch msg := m.GetMessage().(type) {
case *p2p.Message_Ping:
return PingOp, nil
case *p2p.Message_Pong:
return PongOp, nil
case *p2p.Message_Handshake:
return HandshakeOp, nil
case *p2p.Message_GetPeerList:
return GetPeerListOp, nil
case *p2p.Message_PeerList_:
return PeerListOp, nil
case *p2p.Message_GetStateSummaryFrontier:
return GetStateSummaryFrontierOp, nil
case *p2p.Message_StateSummaryFrontier_:
return StateSummaryFrontierOp, nil
case *p2p.Message_GetAcceptedStateSummary:
return GetAcceptedStateSummaryOp, nil
case *p2p.Message_AcceptedStateSummary_:
return AcceptedStateSummaryOp, nil
case *p2p.Message_GetAcceptedFrontier:
return GetAcceptedFrontierOp, nil
case *p2p.Message_AcceptedFrontier_:
return AcceptedFrontierOp, nil
case *p2p.Message_GetAccepted:
return GetAcceptedOp, nil
case *p2p.Message_Accepted_:
return AcceptedOp, nil
case *p2p.Message_GetAncestors:
return GetAncestorsOp, nil
case *p2p.Message_Ancestors_:
return AncestorsOp, nil
case *p2p.Message_Get:
return GetOp, nil
case *p2p.Message_Put:
return PutOp, nil
case *p2p.Message_PushQuery:
return PushQueryOp, nil
case *p2p.Message_PullQuery:
return PullQueryOp, nil
case *p2p.Message_Chits:
return QbitOp, nil
case *p2p.Message_Request:
return RequestOp, nil
case *p2p.Message_Response:
return ResponseOp, nil
case *p2p.Message_Error:
return ErrorOp, nil
case *p2p.Message_Gossip:
return GossipOp, nil
case *p2p.Message_BFT:
return BFTOp, nil
default:
return 0, fmt.Errorf("%w: %T", errUnknownMessageType, msg)
}
}
+752
View File
@@ -0,0 +1,752 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package message
import (
"net/netip"
"time"
compression "github.com/luxfi/compress"
"github.com/luxfi/ids"
"github.com/luxfi/net/endpoints"
"github.com/luxfi/node/proto/p2p"
)
var _ OutboundMsgBuilder = (*outMsgBuilder)(nil)
// OutboundMsgBuilder builds outbound messages. Outbound messages are returned
// with a reference count of 1. Once the reference count hits 0, the message
// bytes should no longer be accessed.
type OutboundMsgBuilder interface {
Handshake(
networkID uint32,
myTime uint64,
ip netip.AddrPort,
client string,
major uint32,
minor uint32,
patch uint32,
ipSigningTime uint64,
ipNodeIDSig []byte,
ipBLSSig []byte,
trackedNets []ids.ID,
supportedLPs []uint32,
objectedLPs []uint32,
knownPeersFilter []byte,
knownPeersSalt []byte,
requestAllNetIPs bool,
) (OutboundMessage, error)
GetPeerList(
knownPeersFilter []byte,
knownPeersSalt []byte,
requestAllNetIPs bool,
) (OutboundMessage, error)
PeerList(
peers []*endpoints.ClaimedIPPort,
bypassThrottling bool,
) (OutboundMessage, error)
Ping(
primaryUptime uint32,
) (OutboundMessage, error)
Pong() (OutboundMessage, error)
GetStateSummaryFrontier(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
) (OutboundMessage, error)
StateSummaryFrontier(
chainID ids.ID,
requestID uint32,
summary []byte,
) (OutboundMessage, error)
GetAcceptedStateSummary(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
heights []uint64,
) (OutboundMessage, error)
AcceptedStateSummary(
chainID ids.ID,
requestID uint32,
summaryIDs []ids.ID,
) (OutboundMessage, error)
GetAcceptedFrontier(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
) (OutboundMessage, error)
AcceptedFrontier(
chainID ids.ID,
requestID uint32,
containerID ids.ID,
) (OutboundMessage, error)
GetAccepted(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
containerIDs []ids.ID,
) (OutboundMessage, error)
Accepted(
chainID ids.ID,
requestID uint32,
containerIDs []ids.ID,
) (OutboundMessage, error)
GetAncestors(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
containerID ids.ID,
engineType p2p.EngineType,
) (OutboundMessage, error)
Ancestors(
chainID ids.ID,
requestID uint32,
containers [][]byte,
) (OutboundMessage, error)
Get(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
containerID ids.ID,
) (OutboundMessage, error)
Put(
chainID ids.ID,
requestID uint32,
container []byte,
) (OutboundMessage, error)
PushQuery(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
container []byte,
requestedHeight uint64,
) (OutboundMessage, error)
PullQuery(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
containerID ids.ID,
requestedHeight uint64,
) (OutboundMessage, error)
Chits(
chainID ids.ID,
requestID uint32,
preferredID ids.ID,
preferredIDAtHeight ids.ID,
acceptedID ids.ID,
acceptedHeight uint64,
) (OutboundMessage, error)
Request(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
msg []byte,
) (OutboundMessage, error)
Response(
chainID ids.ID,
requestID uint32,
msg []byte,
) (OutboundMessage, error)
Error(
chainID ids.ID,
requestID uint32,
errorCode int32,
errorMessage string,
) (OutboundMessage, error)
Gossip(
chainID ids.ID,
msg []byte,
) (OutboundMessage, error)
BFTMessage(
msg *p2p.BFT,
) (OutboundMessage, error)
}
type outMsgBuilder struct {
compressionType compression.Type
builder *msgBuilder
}
// Use "message.NewCreator" to import this function
// since we do not expose "msgBuilder" yet
func newOutboundBuilder(compressionType compression.Type, builder *msgBuilder) OutboundMsgBuilder {
return &outMsgBuilder{
compressionType: compressionType,
builder: builder,
}
}
// ... ping/pong omitted for brevity in prompt, only replacing targeted section ...
// Wait, replace_file_content replaces a chunk. I need to target the Interface definitions and Implementation.
// Interface is lines 160-188.
// Implementation is lines 663-731.
// I should use 2 ReplaceFile calls or one if contiguous? They are NOT contiguous.
// I can use `multi_replace_file_content`? Or `replace_file_content` twice.
// I'll do Interface first.
// Oh wait, `replace_file_content` only allows ONE chunk.
// I'll use separate calls or `multi_replace`.
// I'll use `multi_replace_file_content` for `outbound_msg_builder.go`.
func (b *outMsgBuilder) Ping(
primaryUptime uint32,
) (OutboundMessage, error) {
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_Ping{
Ping: &p2p.Ping{
Uptime: primaryUptime,
},
},
},
compression.TypeNone,
false,
)
}
func (b *outMsgBuilder) Pong() (OutboundMessage, error) {
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_Pong{
Pong: &p2p.Pong{},
},
},
compression.TypeNone,
false,
)
}
func (b *outMsgBuilder) Handshake(
networkID uint32,
myTime uint64,
ip netip.AddrPort,
client string,
major uint32,
minor uint32,
patch uint32,
ipSigningTime uint64,
ipNodeIDSig []byte,
ipBLSSig []byte,
trackedNets []ids.ID,
supportedLPs []uint32,
objectedLPs []uint32,
knownPeersFilter []byte,
knownPeersSalt []byte,
requestAllNetIPs bool,
) (OutboundMessage, error) {
subsubchainIDBytes := make([][]byte, len(trackedNets))
encodeIDs(trackedNets, subsubchainIDBytes)
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_Handshake{
Handshake: &p2p.Handshake{
NetworkId: networkID,
MyTime: myTime,
IpAddr: ip.Addr().AsSlice(),
IpPort: uint32(ip.Port()),
IpSigningTime: ipSigningTime,
IpNodeIdSig: ipNodeIDSig,
TrackedNets: subsubchainIDBytes,
Client: &p2p.Client{
Name: client,
Major: major,
Minor: minor,
Patch: patch,
},
SupportedLps: supportedLPs,
ObjectedLps: objectedLPs,
KnownPeers: &p2p.BloomFilter{
Filter: knownPeersFilter,
Salt: knownPeersSalt,
},
IpBlsSig: ipBLSSig,
AllChains: requestAllNetIPs,
},
},
},
compression.TypeNone,
true,
)
}
func (b *outMsgBuilder) GetPeerList(
knownPeersFilter []byte,
knownPeersSalt []byte,
requestAllNetIPs bool,
) (OutboundMessage, error) {
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_GetPeerList{
GetPeerList: &p2p.GetPeerList{
KnownPeers: &p2p.BloomFilter{
Filter: knownPeersFilter,
Salt: knownPeersSalt,
},
AllChains: requestAllNetIPs,
},
},
},
b.compressionType,
false,
)
}
func (b *outMsgBuilder) PeerList(peers []*endpoints.ClaimedIPPort, bypassThrottling bool) (OutboundMessage, error) {
claimIPPorts := make([]*p2p.ClaimedIpPort, len(peers))
for i, p := range peers {
claimIPPorts[i] = &p2p.ClaimedIpPort{
X509Certificate: p.Cert.Raw,
IpAddr: p.AddrPort.Addr().AsSlice(),
IpPort: uint32(p.AddrPort.Port()),
Timestamp: p.Timestamp,
Signature: p.Signature,
TxId: ids.Empty[:],
}
}
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_PeerList_{
PeerList_: &p2p.PeerList{
ClaimedIpPorts: claimIPPorts,
},
},
},
b.compressionType,
bypassThrottling,
)
}
func (b *outMsgBuilder) GetStateSummaryFrontier(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
) (OutboundMessage, error) {
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_GetStateSummaryFrontier{
GetStateSummaryFrontier: &p2p.GetStateSummaryFrontier{
ChainId: chainID[:],
RequestId: requestID,
Deadline: uint64(deadline),
},
},
},
compression.TypeNone,
false,
)
}
func (b *outMsgBuilder) StateSummaryFrontier(
chainID ids.ID,
requestID uint32,
summary []byte,
) (OutboundMessage, error) {
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_StateSummaryFrontier_{
StateSummaryFrontier_: &p2p.StateSummaryFrontier{
ChainId: chainID[:],
RequestId: requestID,
Summary: summary,
},
},
},
b.compressionType,
false,
)
}
func (b *outMsgBuilder) GetAcceptedStateSummary(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
heights []uint64,
) (OutboundMessage, error) {
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_GetAcceptedStateSummary{
GetAcceptedStateSummary: &p2p.GetAcceptedStateSummary{
ChainId: chainID[:],
RequestId: requestID,
Deadline: uint64(deadline),
Heights: heights,
},
},
},
b.compressionType,
false,
)
}
func (b *outMsgBuilder) AcceptedStateSummary(
chainID ids.ID,
requestID uint32,
summaryIDs []ids.ID,
) (OutboundMessage, error) {
summaryIDBytes := make([][]byte, len(summaryIDs))
encodeIDs(summaryIDs, summaryIDBytes)
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_AcceptedStateSummary_{
AcceptedStateSummary_: &p2p.AcceptedStateSummary{
ChainId: chainID[:],
RequestId: requestID,
SummaryIds: summaryIDBytes,
},
},
},
b.compressionType,
false,
)
}
func (b *outMsgBuilder) GetAcceptedFrontier(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
) (OutboundMessage, error) {
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_GetAcceptedFrontier{
GetAcceptedFrontier: &p2p.GetAcceptedFrontier{
ChainId: chainID[:],
RequestId: requestID,
Deadline: uint64(deadline),
},
},
},
compression.TypeNone,
false,
)
}
func (b *outMsgBuilder) AcceptedFrontier(
chainID ids.ID,
requestID uint32,
containerID ids.ID,
) (OutboundMessage, error) {
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_AcceptedFrontier_{
AcceptedFrontier_: &p2p.AcceptedFrontier{
ChainId: chainID[:],
RequestId: requestID,
ContainerId: containerID[:],
},
},
},
compression.TypeNone,
false,
)
}
func (b *outMsgBuilder) GetAccepted(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
containerIDs []ids.ID,
) (OutboundMessage, error) {
containerIDBytes := make([][]byte, len(containerIDs))
encodeIDs(containerIDs, containerIDBytes)
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_GetAccepted{
GetAccepted: &p2p.GetAccepted{
ChainId: chainID[:],
RequestId: requestID,
Deadline: uint64(deadline),
ContainerIds: containerIDBytes,
},
},
},
compression.TypeNone,
false,
)
}
func (b *outMsgBuilder) Accepted(
chainID ids.ID,
requestID uint32,
containerIDs []ids.ID,
) (OutboundMessage, error) {
containerIDBytes := make([][]byte, len(containerIDs))
encodeIDs(containerIDs, containerIDBytes)
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_Accepted_{
Accepted_: &p2p.Accepted{
ChainId: chainID[:],
RequestId: requestID,
ContainerIds: containerIDBytes,
},
},
},
compression.TypeNone,
false,
)
}
func (b *outMsgBuilder) GetAncestors(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
containerID ids.ID,
engineType p2p.EngineType,
) (OutboundMessage, error) {
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_GetAncestors{
GetAncestors: &p2p.GetAncestors{
ChainId: chainID[:],
RequestId: requestID,
Deadline: uint64(deadline),
ContainerId: containerID[:],
EngineType: engineType,
},
},
},
compression.TypeNone,
false,
)
}
func (b *outMsgBuilder) Ancestors(
chainID ids.ID,
requestID uint32,
containers [][]byte,
) (OutboundMessage, error) {
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_Ancestors_{
Ancestors_: &p2p.Ancestors{
ChainId: chainID[:],
RequestId: requestID,
Containers: containers,
},
},
},
b.compressionType,
false,
)
}
func (b *outMsgBuilder) Get(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
containerID ids.ID,
) (OutboundMessage, error) {
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_Get{
Get: &p2p.Get{
ChainId: chainID[:],
RequestId: requestID,
Deadline: uint64(deadline),
ContainerId: containerID[:],
},
},
},
compression.TypeNone,
false,
)
}
func (b *outMsgBuilder) Put(
chainID ids.ID,
requestID uint32,
container []byte,
) (OutboundMessage, error) {
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_Put{
Put: &p2p.Put{
ChainId: chainID[:],
RequestId: requestID,
Container: container,
},
},
},
b.compressionType,
false,
)
}
func (b *outMsgBuilder) PushQuery(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
container []byte,
requestedHeight uint64,
) (OutboundMessage, error) {
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_PushQuery{
PushQuery: &p2p.PushQuery{
ChainId: chainID[:],
RequestId: requestID,
Deadline: uint64(deadline),
Container: container,
RequestedHeight: requestedHeight,
},
},
},
b.compressionType,
false,
)
}
func (b *outMsgBuilder) PullQuery(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
containerID ids.ID,
requestedHeight uint64,
) (OutboundMessage, error) {
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_PullQuery{
PullQuery: &p2p.PullQuery{
ChainId: chainID[:],
RequestId: requestID,
Deadline: uint64(deadline),
ContainerId: containerID[:],
RequestedHeight: requestedHeight,
},
},
},
compression.TypeNone,
false,
)
}
func (b *outMsgBuilder) Chits(
chainID ids.ID,
requestID uint32,
preferredID ids.ID,
preferredIDAtHeight ids.ID,
acceptedID ids.ID,
acceptedHeight uint64,
) (OutboundMessage, error) {
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_Chits{
Chits: &p2p.Chits{
ChainId: chainID[:],
RequestId: requestID,
PreferredId: preferredID[:],
PreferredIdAtHeight: preferredIDAtHeight[:],
AcceptedId: acceptedID[:],
AcceptedHeight: acceptedHeight,
},
},
},
compression.TypeNone,
false,
)
}
func (b *outMsgBuilder) Request(
chainID ids.ID,
requestID uint32,
deadline time.Duration,
msg []byte,
) (OutboundMessage, error) {
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_Request{
Request: &p2p.Request{
ChainId: chainID[:],
RequestId: requestID,
Deadline: uint64(deadline),
AppBytes: msg,
},
},
},
b.compressionType,
false,
)
}
func (b *outMsgBuilder) Response(chainID ids.ID, requestID uint32, msg []byte) (OutboundMessage, error) {
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_Response{
Response: &p2p.Response{
ChainId: chainID[:],
RequestId: requestID,
AppBytes: msg,
},
},
},
b.compressionType,
false,
)
}
func (b *outMsgBuilder) Error(chainID ids.ID, requestID uint32, errorCode int32, errorMessage string) (OutboundMessage, error) {
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_Error{
Error: &p2p.Error{
ChainId: chainID[:],
RequestId: requestID,
ErrorCode: errorCode,
ErrorMessage: errorMessage,
},
},
},
b.compressionType,
false,
)
}
func (b *outMsgBuilder) Gossip(chainID ids.ID, msg []byte) (OutboundMessage, error) {
return b.builder.createOutbound(
&p2p.Message{
Message: &p2p.Message_Gossip{
Gossip: &p2p.Gossip{
ChainId: chainID[:],
AppBytes: msg,
},
},
},
b.compressionType,
false,
)
}
func (b *outMsgBuilder) BFTMessage(msg *p2p.BFT) (OutboundMessage, error) {
return b.builder.createOutbound(
&p2p.Message{
Message: newMessageBFT(msg),
},
b.compressionType,
false,
)
}
+43
View File
@@ -0,0 +1,43 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package message
import (
"testing"
"time"
"github.com/stretchr/testify/require"
compression "github.com/luxfi/compress"
"github.com/luxfi/ids"
"github.com/luxfi/metric"
)
func Test_newOutboundBuilder(t *testing.T) {
t.Parallel()
mb, err := newMsgBuilder(
metric.NewRegistry(),
10*time.Second,
)
require.NoError(t, err)
for _, compressionType := range []compression.Type{
compression.TypeNone,
compression.TypeZstd,
} {
t.Run(compressionType.String(), func(t *testing.T) {
builder := newOutboundBuilder(compressionType, mb)
outMsg, err := builder.GetAcceptedStateSummary(
ids.GenerateTestID(),
12345,
time.Hour,
[]uint64{1000, 2000},
)
require.NoError(t, err)
t.Logf("outbound message with compression type %s built message with size %d", compressionType, len(outMsg.Bytes()))
})
}
}
+327
View File
@@ -0,0 +1,327 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
// Package wire defines P2P message types for network communication.
// This package is wire-format agnostic - encoding is handled by the parent message package.
package wire
// EngineType represents the consensus engine type
type EngineType int32
const (
EngineType_UNSPECIFIED EngineType = 0
EngineType_CHAIN EngineType = 1
EngineType_DAG EngineType = 2
)
// Message is the top-level P2P message container
type Message struct {
// Only one of these should be set
CompressedZstd []byte
Ping *Ping
Pong *Pong
Handshake *Handshake
GetPeerList *GetPeerList
PeerList *PeerList
GetStateSummaryFrontier *GetStateSummaryFrontier
StateSummaryFrontier *StateSummaryFrontier
GetAcceptedStateSummary *GetAcceptedStateSummary
AcceptedStateSummary *AcceptedStateSummary
GetAcceptedFrontier *GetAcceptedFrontier
AcceptedFrontier *AcceptedFrontier
GetAccepted *GetAccepted
Accepted *Accepted
GetAncestors *GetAncestors
Ancestors *Ancestors
Get *Get
Put *Put
PushQuery *PushQuery
PullQuery *PullQuery
Chits *Chits
Request *Request
Response *Response
Gossip *Gossip
BFT *BFT
}
// Ping message
type Ping struct {
Uptime uint32
ChainSubnetPairs []*ChainSubnetPair
}
// ChainSubnetPair for ping
type ChainSubnetPair struct {
ChainId []byte
SubnetId []byte
}
// Pong message
type Pong struct {
Uptime uint32
ChainSubnetPairs []*ChainSubnetPair
}
// Handshake message
type Handshake struct {
NetworkId uint32
MyTime uint64
IpAddr []byte
IpPort uint32
IpSigningTime uint64
IpNodeIdSig []byte
TrackedSubnets [][]byte
Client *Client
SupportedAcps []uint32
ObjectedAcps []uint32
KnownPeers *BloomFilter
IpBlsSig []byte
}
// Client info in handshake
type Client struct {
Name string
Major uint32
Minor uint32
Patch uint32
}
// BloomFilter for peer discovery
type BloomFilter struct {
Filter []byte
Salt []byte
}
// GetPeerList message
type GetPeerList struct {
KnownPeers *BloomFilter
}
// PeerList message
type PeerList struct {
ClaimedIpPorts []*ClaimedIpPort
}
// ClaimedIpPort in peer list
type ClaimedIpPort struct {
X509Certificate []byte
IpAddr []byte
IpPort uint32
Timestamp uint64
Signature []byte
TxId []byte
}
// GetStateSummaryFrontier message
type GetStateSummaryFrontier struct {
ChainId []byte
RequestId uint32
Deadline uint64
}
func (m *GetStateSummaryFrontier) GetChainId() []byte { return m.ChainId }
func (m *GetStateSummaryFrontier) GetRequestId() uint32 { return m.RequestId }
func (m *GetStateSummaryFrontier) GetDeadline() uint64 { return m.Deadline }
// StateSummaryFrontier message
type StateSummaryFrontier struct {
ChainId []byte
RequestId uint32
Summary []byte
}
func (m *StateSummaryFrontier) GetChainId() []byte { return m.ChainId }
func (m *StateSummaryFrontier) GetRequestId() uint32 { return m.RequestId }
// GetAcceptedStateSummary message
type GetAcceptedStateSummary struct {
ChainId []byte
RequestId uint32
Deadline uint64
Heights []uint64
}
func (m *GetAcceptedStateSummary) GetChainId() []byte { return m.ChainId }
func (m *GetAcceptedStateSummary) GetRequestId() uint32 { return m.RequestId }
func (m *GetAcceptedStateSummary) GetDeadline() uint64 { return m.Deadline }
// AcceptedStateSummary message
type AcceptedStateSummary struct {
ChainId []byte
RequestId uint32
SummaryIds [][]byte
}
func (m *AcceptedStateSummary) GetChainId() []byte { return m.ChainId }
func (m *AcceptedStateSummary) GetRequestId() uint32 { return m.RequestId }
// GetAcceptedFrontier message
type GetAcceptedFrontier struct {
ChainId []byte
RequestId uint32
Deadline uint64
EngineType EngineType
}
func (m *GetAcceptedFrontier) GetChainId() []byte { return m.ChainId }
func (m *GetAcceptedFrontier) GetRequestId() uint32 { return m.RequestId }
func (m *GetAcceptedFrontier) GetDeadline() uint64 { return m.Deadline }
// AcceptedFrontier message
type AcceptedFrontier struct {
ChainId []byte
RequestId uint32
ContainerId []byte
}
func (m *AcceptedFrontier) GetChainId() []byte { return m.ChainId }
func (m *AcceptedFrontier) GetRequestId() uint32 { return m.RequestId }
// GetAccepted message
type GetAccepted struct {
ChainId []byte
RequestId uint32
Deadline uint64
ContainerIds [][]byte
EngineType EngineType
}
func (m *GetAccepted) GetChainId() []byte { return m.ChainId }
func (m *GetAccepted) GetRequestId() uint32 { return m.RequestId }
func (m *GetAccepted) GetDeadline() uint64 { return m.Deadline }
// Accepted message
type Accepted struct {
ChainId []byte
RequestId uint32
ContainerIds [][]byte
}
func (m *Accepted) GetChainId() []byte { return m.ChainId }
func (m *Accepted) GetRequestId() uint32 { return m.RequestId }
// GetAncestors message
type GetAncestors struct {
ChainId []byte
RequestId uint32
Deadline uint64
ContainerId []byte
EngineType EngineType
}
func (m *GetAncestors) GetChainId() []byte { return m.ChainId }
func (m *GetAncestors) GetRequestId() uint32 { return m.RequestId }
func (m *GetAncestors) GetDeadline() uint64 { return m.Deadline }
func (m *GetAncestors) GetEngineType() EngineType { return m.EngineType }
// Ancestors message
type Ancestors struct {
ChainId []byte
RequestId uint32
Containers [][]byte
}
func (m *Ancestors) GetChainId() []byte { return m.ChainId }
func (m *Ancestors) GetRequestId() uint32 { return m.RequestId }
// Get message
type Get struct {
ChainId []byte
RequestId uint32
Deadline uint64
ContainerId []byte
EngineType EngineType
}
func (m *Get) GetChainId() []byte { return m.ChainId }
func (m *Get) GetRequestId() uint32 { return m.RequestId }
func (m *Get) GetDeadline() uint64 { return m.Deadline }
// Put message
type Put struct {
ChainId []byte
RequestId uint32
Container []byte
EngineType EngineType
}
func (m *Put) GetChainId() []byte { return m.ChainId }
func (m *Put) GetRequestId() uint32 { return m.RequestId }
// PushQuery message
type PushQuery struct {
ChainId []byte
RequestId uint32
Deadline uint64
Container []byte
EngineType EngineType
RequestedHeight uint64
}
func (m *PushQuery) GetChainId() []byte { return m.ChainId }
func (m *PushQuery) GetRequestId() uint32 { return m.RequestId }
func (m *PushQuery) GetDeadline() uint64 { return m.Deadline }
// PullQuery message
type PullQuery struct {
ChainId []byte
RequestId uint32
Deadline uint64
ContainerId []byte
EngineType EngineType
RequestedHeight uint64
}
func (m *PullQuery) GetChainId() []byte { return m.ChainId }
func (m *PullQuery) GetRequestId() uint32 { return m.RequestId }
func (m *PullQuery) GetDeadline() uint64 { return m.Deadline }
// Chits message
type Chits struct {
ChainId []byte
RequestId uint32
PreferredId []byte
PreferredIdAtHeight []byte
AcceptedId []byte
}
func (m *Chits) GetChainId() []byte { return m.ChainId }
func (m *Chits) GetRequestId() uint32 { return m.RequestId }
// Request message (app-level)
type Request struct {
ChainId []byte
RequestId uint32
Deadline uint64
Request []byte
}
func (m *Request) GetChainId() []byte { return m.ChainId }
func (m *Request) GetRequestId() uint32 { return m.RequestId }
func (m *Request) GetDeadline() uint64 { return m.Deadline }
// Response message (app-level)
type Response struct {
ChainId []byte
RequestId uint32
Response []byte
}
func (m *Response) GetChainId() []byte { return m.ChainId }
func (m *Response) GetRequestId() uint32 { return m.RequestId }
// Gossip message (app-level)
type Gossip struct {
ChainId []byte
Gossip []byte
}
func (m *Gossip) GetChainId() []byte { return m.ChainId }
// BFT message
type BFT struct {
ChainId []byte
Message []byte
}
func (m *BFT) GetChainId() []byte { return m.ChainId }
+1150
View File
File diff suppressed because it is too large Load Diff