2022-05-16 13:28:03 +00:00
|
|
|
package sentry
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/ledgerwatch/erigon-lib/gointerfaces"
|
|
|
|
proto_sentry "github.com/ledgerwatch/erigon-lib/gointerfaces/sentry"
|
|
|
|
"github.com/ledgerwatch/erigon/core/forkid"
|
|
|
|
"github.com/ledgerwatch/erigon/eth/protocols/eth"
|
|
|
|
"github.com/ledgerwatch/erigon/p2p"
|
|
|
|
)
|
|
|
|
|
|
|
|
func readAndValidatePeerStatusMessage(
|
|
|
|
rw p2p.MsgReadWriter,
|
|
|
|
status *proto_sentry.StatusData,
|
|
|
|
version uint,
|
|
|
|
minVersion uint,
|
2023-08-31 15:45:23 +00:00
|
|
|
) (*eth.StatusPacket, *p2p.PeerError) {
|
2022-05-16 13:28:03 +00:00
|
|
|
msg, err := rw.ReadMsg()
|
|
|
|
if err != nil {
|
2023-08-31 15:45:23 +00:00
|
|
|
return nil, p2p.NewPeerError(p2p.PeerErrorStatusReceive, p2p.DiscNetworkError, err, "readAndValidatePeerStatusMessage rw.ReadMsg error")
|
2022-05-16 13:28:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
reply, err := tryDecodeStatusMessage(&msg)
|
|
|
|
msg.Discard()
|
|
|
|
if err != nil {
|
2023-08-31 15:45:23 +00:00
|
|
|
return nil, p2p.NewPeerError(p2p.PeerErrorStatusDecode, p2p.DiscProtocolError, err, "readAndValidatePeerStatusMessage tryDecodeStatusMessage error")
|
2022-05-16 13:28:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
err = checkPeerStatusCompatibility(reply, status, version, minVersion)
|
2023-08-31 15:45:23 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, p2p.NewPeerError(p2p.PeerErrorStatusIncompatible, p2p.DiscUselessPeer, err, "readAndValidatePeerStatusMessage checkPeerStatusCompatibility error")
|
|
|
|
}
|
|
|
|
|
|
|
|
return reply, nil
|
2022-05-16 13:28:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func tryDecodeStatusMessage(msg *p2p.Msg) (*eth.StatusPacket, error) {
|
|
|
|
if msg.Code != eth.StatusMsg {
|
|
|
|
return nil, fmt.Errorf("first msg has code %x (!= %x)", msg.Code, eth.StatusMsg)
|
|
|
|
}
|
|
|
|
|
|
|
|
if msg.Size > eth.ProtocolMaxMsgSize {
|
|
|
|
return nil, fmt.Errorf("message is too large %d, limit %d", msg.Size, eth.ProtocolMaxMsgSize)
|
|
|
|
}
|
|
|
|
|
|
|
|
var reply eth.StatusPacket
|
|
|
|
if err := msg.Decode(&reply); err != nil {
|
|
|
|
return nil, fmt.Errorf("decode message %v: %w", msg, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &reply, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func checkPeerStatusCompatibility(
|
|
|
|
reply *eth.StatusPacket,
|
|
|
|
status *proto_sentry.StatusData,
|
|
|
|
version uint,
|
|
|
|
minVersion uint,
|
|
|
|
) error {
|
|
|
|
networkID := status.NetworkId
|
|
|
|
if reply.NetworkID != networkID {
|
2023-08-31 15:45:23 +00:00
|
|
|
return fmt.Errorf("network id does not match: theirs %d, ours %d", reply.NetworkID, networkID)
|
2022-05-16 13:28:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if uint(reply.ProtocolVersion) > version {
|
|
|
|
return fmt.Errorf("version is more than what this senty supports: theirs %d, max %d", reply.ProtocolVersion, version)
|
|
|
|
}
|
|
|
|
if uint(reply.ProtocolVersion) < minVersion {
|
|
|
|
return fmt.Errorf("version is less than allowed minimum: theirs %d, min %d", reply.ProtocolVersion, minVersion)
|
|
|
|
}
|
|
|
|
|
|
|
|
genesisHash := gointerfaces.ConvertH256ToHash(status.ForkData.Genesis)
|
|
|
|
if reply.Genesis != genesisHash {
|
|
|
|
return fmt.Errorf("genesis hash does not match: theirs %x, ours %x", reply.Genesis, genesisHash)
|
|
|
|
}
|
|
|
|
|
2022-12-16 11:08:54 +00:00
|
|
|
forkFilter := forkid.NewFilterFromForks(status.ForkData.HeightForks, status.ForkData.TimeForks, genesisHash, status.MaxBlockHeight, status.MaxBlockTime)
|
|
|
|
return forkFilter(reply.ForkID)
|
2022-05-16 13:28:03 +00:00
|
|
|
}
|