Check capabilities of own server before sending anything that requires it

This commit is contained in:
DataHoarder 2023-07-31 21:40:36 +02:00
parent d52710eea4
commit f49f52a853
Signed by: DataHoarder
SSH key fingerprint: SHA256:OLTRf6Fl87G52SiR7sWLGNzlJt4WOX+tfI2yxo0z7xk
3 changed files with 62 additions and 16 deletions

View file

@ -472,7 +472,7 @@ func (c *Client) OnConnection() {
}
}
if block != nil && c.VersionInformation.SupportsFeature(p2pooltypes.FeatureBlockNotify) {
if block != nil && c.Owner.VersionInformation().SupportsFeature(p2pooltypes.FeatureBlockNotify) && c.VersionInformation.SupportsFeature(p2pooltypes.FeatureBlockNotify) {
c.SendBlockNotify(block.Side.Parent)
for _, uncleId := range block.Side.Uncles {
c.SendBlockNotify(uncleId)
@ -694,12 +694,13 @@ func (c *Client) OnConnection() {
}
}
if c.LastIncomingPeerListRequestTime.IsZero() {
// Check whether to send version to target or not
if c.LastIncomingPeerListRequestTime.IsZero() && c.Owner.VersionInformation().SupportsFeature(p2pooltypes.FeaturePeerInformationExchange) && c.VersionInformation.SupportsFeature(p2pooltypes.FeaturePeerInformationReceive) {
//first, send version / protocol information
if len(entriesToSend) == 0 {
entriesToSend = append(entriesToSend, c.Owner.versionInformation.ToAddrPort())
entriesToSend = append(entriesToSend, c.Owner.VersionInformation().ToAddrPort())
} else {
entriesToSend[0] = c.Owner.versionInformation.ToAddrPort()
entriesToSend[0] = c.Owner.VersionInformation().ToAddrPort()
}
}

View file

@ -796,28 +796,39 @@ func (s *Server) MainChain() *mainchain.MainChain {
func (s *Server) Broadcast(block *sidechain.PoolBlock) {
var message, prunedMessage, compactMessage *ClientMessage
if block != nil {
blockData, err := block.AppendBinaryFlags(make([]byte, 0, block.BufferLength()), false, false)
// Full block broadcast
buffer := make([]byte, 4, block.BufferLength()+4)
blockData, err := block.AppendBinaryFlags(buffer, false, false)
if err != nil {
log.Panicf("[P2PServer] Tried to broadcast block %s at height %d but received error: %s", block.SideTemplateId(s.Consensus()), block.Side.Height, err)
return
}
binary.LittleEndian.PutUint32(blockData, uint32(len(blockData)-4))
message = &ClientMessage{
MessageId: MessageBlockBroadcast,
Buffer: append(binary.LittleEndian.AppendUint32(make([]byte, 0, len(blockData)+4), uint32(len(blockData))), blockData...),
Buffer: blockData,
}
prunedBlockData, _ := block.AppendBinaryFlags(make([]byte, 0, block.BufferLength()), true, false)
// Pruned block broadcast
prunedBuffer := make([]byte, 4, block.BufferLength()+4)
prunedBlockData, _ := block.AppendBinaryFlags(prunedBuffer, true, false)
binary.LittleEndian.PutUint32(prunedBlockData, uint32(len(prunedBlockData)-4))
prunedMessage = &ClientMessage{
MessageId: MessageBlockBroadcast,
Buffer: append(binary.LittleEndian.AppendUint32(make([]byte, 0, len(prunedBlockData)+4), uint32(len(prunedBlockData))), prunedBlockData...),
Buffer: prunedBlockData,
}
compactBlockData, _ := block.AppendBinaryFlags(make([]byte, 0, block.BufferLength()), true, true)
// Compact block broadcast
compactBuffer := make([]byte, 4, block.BufferLength()+4)
compactBlockData, _ := block.AppendBinaryFlags(compactBuffer, true, true)
binary.LittleEndian.PutUint32(compactBlockData, uint32(len(compactBlockData)-4))
if len(compactBlockData) >= len(prunedBlockData) {
//do not send compact if it ends up larger due to some reason, like parent missing or mismatch in transactions
compactMessage = prunedMessage
} else {
compactMessage = &ClientMessage{
prunedMessage = &ClientMessage{
MessageId: MessageBlockBroadcastCompact,
Buffer: append(binary.LittleEndian.AppendUint32(make([]byte, 0, len(compactBlockData)+4), uint32(len(compactBlockData))), compactBlockData...),
Buffer: compactBlockData,
}
}
} else {
@ -828,6 +839,16 @@ func (s *Server) Broadcast(block *sidechain.PoolBlock) {
prunedMessage, compactMessage = message, message
}
if !s.versionInformation.SupportsFeature(p2pooltypes.FeaturePrunedBroadcast) {
prunedMessage = message
}
if !s.versionInformation.SupportsFeature(p2pooltypes.FeatureCompactBroadcast) {
compactMessage = prunedMessage
}
supportsNotify := s.versionInformation.SupportsFeature(p2pooltypes.FeatureBlockNotify)
blockTemplateId := block.SideTemplateId(s.Consensus())
go func() {
@ -849,17 +870,19 @@ func (s *Server) Broadcast(block *sidechain.PoolBlock) {
// has peer broadcasted this block to us?
if slices.Index(broadcastedHashes, blockTemplateId) != -1 &&
c.VersionInformation.SupportsFeature(p2pooltypes.FeatureBlockNotify) {
supportsNotify && c.VersionInformation.SupportsFeature(p2pooltypes.FeatureBlockNotify) {
c.SendBlockNotify(blockTemplateId)
return true
}
if c.VersionInformation.SupportsFeature(p2pooltypes.FeatureCompactBroadcast) {
c.SendMessage(compactMessage)
} else {
return true
} else if c.VersionInformation.SupportsFeature(p2pooltypes.FeaturePrunedBroadcast) {
c.SendMessage(prunedMessage)
return true
}
return true
return false
}() {
//fallback
c.SendMessage(message)

View file

@ -3,6 +3,7 @@ package types
import (
"bytes"
"encoding/binary"
"encoding/hex"
"fmt"
"net/netip"
)
@ -15,10 +16,16 @@ func IsPeerVersionInformation(addr netip.AddrPort) bool {
return bytes.Compare(rawIp[12:], []byte{0xFF, 0xFF, 0xFF, 0xFF}) == 0
}
// ProtocolFeature List of features to check to not depend on hardcoded protocol versions.
// Use PeerVersionInformation.SupportsFeature() to query these.
type ProtocolFeature int
const (
FeatureCompactBroadcast = ProtocolFeature(iota)
// FeaturePeerInformationReceive Backwards compatible, can be sent to all clients
FeaturePeerInformationReceive = ProtocolFeature(iota)
FeaturePeerInformationExchange
FeaturePrunedBroadcast
FeatureCompactBroadcast
FeatureBlockNotify
)
@ -30,6 +37,12 @@ type PeerVersionInformation struct {
func (i *PeerVersionInformation) SupportsFeature(feature ProtocolFeature) bool {
switch feature {
case FeaturePeerInformationReceive:
return i.Protocol == ProtocolVersion_0_0 || i.Protocol >= ProtocolVersion_1_0
case FeaturePeerInformationExchange:
return i.Protocol >= ProtocolVersion_1_0
case FeaturePrunedBroadcast:
return i.Protocol == ProtocolVersion_0_0 || i.Protocol >= ProtocolVersion_1_0
case FeatureCompactBroadcast:
return i.Protocol >= ProtocolVersion_1_1
case FeatureBlockNotify:
@ -40,6 +53,11 @@ func (i *PeerVersionInformation) SupportsFeature(feature ProtocolFeature) bool {
}
func (i *PeerVersionInformation) String() string {
// Empty information
if i.Protocol == 0 && i.SoftwareVersion == 0 && i.SoftwareId == 0 {
return "Unknown"
}
return fmt.Sprintf("%s %s (protocol %s)", i.SoftwareId.String(), i.SoftwareVersion.String(), i.Protocol.String())
}
@ -100,7 +118,11 @@ func (c SoftwareId) String() string {
case SoftwareIdGoObserver:
return "GoObserver"
default:
return fmt.Sprintf("Unknown(%08x)", uint32(c))
var buf = [17]byte{'U', 'n', 'k', 'n', 'o', 'w', 'n', '(', 0, 0, 0, 0, 0, 0, 0, 0, ')'}
var intBuf [4]byte
binary.LittleEndian.PutUint32(intBuf[:], uint32(c))
hex.Encode(buf[8:], intBuf[:])
return string(buf[:])
}
}