From ef8a4add96f26244655c7e9fcba37b0e5b49a7e0 Mon Sep 17 00:00:00 2001 From: iowar Date: Sat, 30 Sep 2023 06:08:53 +0300 Subject: [PATCH 1/8] log p2p address --- pkg/p2p/libp2p/libp2p.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pkg/p2p/libp2p/libp2p.go b/pkg/p2p/libp2p/libp2p.go index f020053e..6b5a1afe 100644 --- a/pkg/p2p/libp2p/libp2p.go +++ b/pkg/p2p/libp2p/libp2p.go @@ -101,6 +101,13 @@ func New(opts *Options) (*Service, error) { return nil, err } + for _, addr := range host.Addrs() { + opts.Logger.With( + "addr", addr, + "host", host.ID().Pretty(), + ).Info("p2p address") + } + ethAddress, err := GetEthAddressFromPeerID(host.ID()) if err != nil { return nil, err From 56e1ee8ea25b37b5c5c9400fb59944e34206c8a9 Mon Sep 17 00:00:00 2001 From: iowar Date: Sat, 30 Sep 2023 06:13:03 +0300 Subject: [PATCH 2/8] log disconnected peer --- pkg/topology/topology.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/topology/topology.go b/pkg/topology/topology.go index 8feeb1c3..40ab6023 100644 --- a/pkg/topology/topology.go +++ b/pkg/topology/topology.go @@ -96,6 +96,8 @@ func (t *topology) Disconnected(p p2p.Peer) { t.mu.Lock() defer t.mu.Unlock() + t.logger.With("peer", p).Info("disconnected") + switch p.Type { case p2p.PeerTypeBuilder: delete(t.builders, p.EthAddress) From 64b940fea85568b44675e30cbe9138681abb1bc5 Mon Sep 17 00:00:00 2001 From: iowar Date: Sat, 30 Sep 2023 07:16:38 +0300 Subject: [PATCH 3/8] gater activated [status=allowed] --- pkg/p2p/libp2p/conngater.go | 226 ++++++++++++++++++++++++++++++++++++ pkg/p2p/libp2p/libp2p.go | 3 + 2 files changed, 229 insertions(+) create mode 100644 pkg/p2p/libp2p/conngater.go diff --git a/pkg/p2p/libp2p/conngater.go b/pkg/p2p/libp2p/conngater.go new file mode 100644 index 00000000..8256e846 --- /dev/null +++ b/pkg/p2p/libp2p/conngater.go @@ -0,0 +1,226 @@ +package libp2p + +import ( + "math/big" + + "github.com/libp2p/go-libp2p/core/control" + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/multiformats/go-multiaddr" + "github.com/primevprotocol/mev-commit/pkg/p2p" + "github.com/primevprotocol/mev-commit/pkg/register" +) + +type connectionAllowance int + +const ( + Undecided connectionAllowance = iota + DenyBlockedPeer + DenyNotEnoughStake + DenySearcherToSearcher + Accept +) + +var connectionAllowanceStrings = map[connectionAllowance]string{ + Undecided: "Undecided", + DenyBlockedPeer: "DenyBlockedPeer", + DenyNotEnoughStake: "DenyNotEnoughStake", + DenySearcherToSearcher: "DenySearcherToSearcher", + Accept: "Allow", +} + +func (c connectionAllowance) isDeny() bool { + return !(c == Accept || c == Undecided) +} + +// make sure the connections are between builder<>builder, builder<>searcher! +type ConnectionGater interface { + // InterceptPeerDial intercepts peer dialing + InterceptPeerDial(p peer.ID) (allow bool) + // InterceptAddrDial intercepts address dialing + InterceptAddrDial(peer.ID, multiaddr.Multiaddr) (allow bool) + // InterceptAccept intercepts connection acceptance + InterceptAccept(network.ConnMultiaddrs) (allow bool) + // InterceptSecured intercepts secured connection + InterceptSecured(network.Direction, peer.ID, network.ConnMultiaddrs) (allow bool) + // InterceptUpgraded intercepts upgraded connection + InterceptUpgraded(network.Conn) (allow bool, reason control.DisconnectReason) +} + +type connectionGater struct { + register register.Register + selfType p2p.PeerType + minimumStake *big.Int +} + +// newConnectionGater creates a new instance of ConnectionGater +func newConnectionGater(register register.Register, selfType p2p.PeerType, minimumStake *big.Int) ConnectionGater { + return &connectionGater{ + register: register, + selfType: selfType, + minimumStake: minimumStake, + } +} + +// checkPeerTrusted determines the trust status of a peer +func (cg *connectionGater) checkPeerTrusted(p peer.ID) connectionAllowance { + // TODO: Implement the logic to determine whether the peer is trusted or not + return Undecided +} + +// checkPeerBlocked checks if a peer is blocked and returns the appropriate connection allowance status +func (cg *connectionGater) checkPeerBlocked(p peer.ID) connectionAllowance { + // // check if the peer is in the list of blocked peers, and deny the connection if found + // for _, peerID := range cg.blocker.list() { + // if p == peerID { + // return DenyBlockedPeer + // } + // } + // + // if the peer is not in the blocked list, allow the connection + return Accept +} + +// checkPeerStake checks if a peer has enough stake and returns the appropriate +// connection allowance status +func (cg *connectionGater) checkPeerStake(p peer.ID) connectionAllowance { + //NOTE: Temporarily allow searchers in the whitelist + // for _, v := range config.SearcherPeerIDs { + // pid, _ := peer.Decode(v) + // if p == pid { + // if cg.registerPeer(p, commons.Searcher) { + // return Accept + // } else { + // return DenySearcherToSearcher + // } + // } + // } + // + + ethAddress, err := GetEthAddressFromPeerID(p) + if err != nil { + return DenyBlockedPeer + } + + // get stake + stake, err := cg.register.GetStake(ethAddress) + if err != nil { + return DenyBlockedPeer + } + + // check minimal stake + if stake.Cmp(cg.minimumStake) >= 0 { + //if cg.registerPeer(p, commons.Builder) { + return Accept + //} + } + + // deny the connection if the stake is not enough. + return DenyBlockedPeer +} + +// resolveConnectionAllowance resolves the connection allowance based on trusted and blocked statuses +func resolveConnectionAllowance( + trustedStatus connectionAllowance, + blockedStatus connectionAllowance, +) connectionAllowance { + // if the peer's trusted status is 'Undecided', resolve the connection allowance based on the blocked status + if trustedStatus == Undecided { + return blockedStatus + } + return trustedStatus +} + +// checks if a peer is allowed to dial/accept +func (cg *connectionGater) checkAllowedPeer(p peer.ID) connectionAllowance { + return resolveConnectionAllowance(cg.checkPeerTrusted(p), cg.checkPeerBlocked(p)) +} + +// InterceptPeerDial intercepts the process of dialing a peer +// +// all peer dialing attempts are allowed +func (cg *connectionGater) InterceptPeerDial(p peer.ID) bool { + allowance := cg.checkAllowedPeer(p) + if allowance.isDeny() { + return false + } + + return !cg.checkPeerStake(p).isDeny() +} + +// InterceptAddrDial intercepts the process of dialing an address +// +// all address dialing attempts are allowed +// TODO rate limiter +func (cg *connectionGater) InterceptAddrDial(p peer.ID, addr multiaddr.Multiaddr) bool { + allowance := cg.checkAllowedPeer(p) + if allowance.isDeny() { + return false + } + + return true +} + +// InterceptAccept intercepts the process of accepting a connection +// +// all connection acceptance attempts are allowed +func (cg *connectionGater) InterceptAccept(connMultiaddrs network.ConnMultiaddrs) bool { + return true +} + +// InterceptSecured intercepts a secured connection, regardless of its direction (inbound/outbound) +func (cg *connectionGater) InterceptSecured(dir network.Direction, p peer.ID, connMultiaddrs network.ConnMultiaddrs) bool { + allowance := cg.checkAllowedPeer(p) + if allowance.isDeny() { + return false + } + + // note: we are indifferent to the direction (inbound/outbound) + // if you want to manipulate (inbound/outbound) connections, make the change + // note:if it is desired to not establish a connection with a peer, + // ensure that it is rejected in both incoming and outgoing connections + if dir == network.DirInbound { + return cg.validateInboundConnection(p, connMultiaddrs) + } else { + return cg.validateOutboundConnection(p, connMultiaddrs) + } + + return true +} + +// InterceptUpgraded intercepts the process of upgrading a connection +// +// all connection upgrade attempts are allowed +func (cg *connectionGater) InterceptUpgraded(conn network.Conn) (bool, control.DisconnectReason) { + return true, control.DisconnectReason(0) +} + +// validateInboundConnection validates an inbound connection by extracting its +// public key and performing stake validation if the validation succeeds and +// the peer's stake is greater than minimal stake, the connection is allowed +// otherwise, the connection is rejected +func (cg *connectionGater) validateInboundConnection(p peer.ID, connMultiaddrs network.ConnMultiaddrs) bool { + //cg.metrics.IncomingConnectionCount.Inc() + + allowance := cg.checkPeerStake(p) + if allowance.isDeny() { + return false + } + + return true +} + +// validateOutboundConnection validates an outbound connection by extracting +// its public key and performing stake validation if the validation succeeds +// and the peer's stake is greater than minimal stake, the connection is +// allowed otherwise, the connection is rejected +func (cg *connectionGater) validateOutboundConnection(p peer.ID, connMultiaddrs network.ConnMultiaddrs) bool { + //cg.metrics.OutgoingConnectionCount.Inc() + + allowance := cg.checkPeerStake(p) + if allowance.isDeny() { + return false + } + + return true +} diff --git a/pkg/p2p/libp2p/libp2p.go b/pkg/p2p/libp2p/libp2p.go index 6b5a1afe..6df1e54c 100644 --- a/pkg/p2p/libp2p/libp2p.go +++ b/pkg/p2p/libp2p/libp2p.go @@ -86,8 +86,11 @@ func New(opts *Options) (*Service, error) { return nil, err } + conngtr := newConnectionGater(opts.Register, opts.PeerType, opts.MinimumStake) + host, err := libp2p.New( libp2p.ListenAddrStrings(fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", opts.ListenPort)), + libp2p.ConnectionGater(conngtr), libp2p.Identity(libp2pKey), libp2p.ConnectionManager(connmgr), libp2p.DefaultTransports, From 6dd004a06b40132e90d42d2c262c53066ea9f571 Mon Sep 17 00:00:00 2001 From: iowar Date: Sat, 30 Sep 2023 16:59:12 +0300 Subject: [PATCH 4/8] gater logic between b<>s & b<>b --- pkg/p2p/libp2p/conngater.go | 42 ++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/pkg/p2p/libp2p/conngater.go b/pkg/p2p/libp2p/conngater.go index 8256e846..b6b0cd4f 100644 --- a/pkg/p2p/libp2p/conngater.go +++ b/pkg/p2p/libp2p/conngater.go @@ -1,6 +1,7 @@ package libp2p import ( + "fmt" "math/big" "github.com/libp2p/go-libp2p/core/control" @@ -15,6 +16,8 @@ type connectionAllowance int const ( Undecided connectionAllowance = iota + DenyUnresolvedAddress + DenyBadRegisterCall DenyBlockedPeer DenyNotEnoughStake DenySearcherToSearcher @@ -23,6 +26,8 @@ const ( var connectionAllowanceStrings = map[connectionAllowance]string{ Undecided: "Undecided", + DenyUnresolvedAddress: "DenyUnresolvedAddress", + DenyBadRegisterCall: "DenyBadRegisterCall", DenyBlockedPeer: "DenyBlockedPeer", DenyNotEnoughStake: "DenyNotEnoughStake", DenySearcherToSearcher: "DenySearcherToSearcher", @@ -84,35 +89,34 @@ func (cg *connectionGater) checkPeerBlocked(p peer.ID) connectionAllowance { // checkPeerStake checks if a peer has enough stake and returns the appropriate // connection allowance status func (cg *connectionGater) checkPeerStake(p peer.ID) connectionAllowance { - //NOTE: Temporarily allow searchers in the whitelist - // for _, v := range config.SearcherPeerIDs { - // pid, _ := peer.Decode(v) - // if p == pid { - // if cg.registerPeer(p, commons.Searcher) { - // return Accept - // } else { - // return DenySearcherToSearcher - // } - // } - // } - // - + // get eth address ethAddress, err := GetEthAddressFromPeerID(p) if err != nil { - return DenyBlockedPeer + return DenyUnresolvedAddress } // get stake stake, err := cg.register.GetStake(ethAddress) if err != nil { - return DenyBlockedPeer + return DenyBadRegisterCall + } + + enoughStake := stake.Cmp(cg.minimumStake) >= 0 + + // s<>b connection + if (cg.selfType == p2p.PeerTypeSearcher) && enoughStake { + return Accept } - // check minimal stake - if stake.Cmp(cg.minimumStake) >= 0 { - //if cg.registerPeer(p, commons.Builder) { + // b<>b connection + if (cg.selfType == p2p.PeerTypeBuilder) && enoughStake { + fmt.Println("--") return Accept - //} + } + + // ! s<>s connection + if (cg.selfType == p2p.PeerTypeSearcher) && !enoughStake { + return DenySearcherToSearcher } // deny the connection if the stake is not enough. From c7d5628c6228e128fed623c84bfa51b35a9163f6 Mon Sep 17 00:00:00 2001 From: iowar Date: Sat, 30 Sep 2023 17:02:45 +0300 Subject: [PATCH 5/8] todo blocker --- pkg/p2p/libp2p/conngater.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/p2p/libp2p/conngater.go b/pkg/p2p/libp2p/conngater.go index b6b0cd4f..598524ea 100644 --- a/pkg/p2p/libp2p/conngater.go +++ b/pkg/p2p/libp2p/conngater.go @@ -1,7 +1,6 @@ package libp2p import ( - "fmt" "math/big" "github.com/libp2p/go-libp2p/core/control" @@ -73,6 +72,7 @@ func (cg *connectionGater) checkPeerTrusted(p peer.ID) connectionAllowance { return Undecided } +// TODO @iowar blocker implementation: consult the team // checkPeerBlocked checks if a peer is blocked and returns the appropriate connection allowance status func (cg *connectionGater) checkPeerBlocked(p peer.ID) connectionAllowance { // // check if the peer is in the list of blocked peers, and deny the connection if found @@ -110,7 +110,6 @@ func (cg *connectionGater) checkPeerStake(p peer.ID) connectionAllowance { // b<>b connection if (cg.selfType == p2p.PeerTypeBuilder) && enoughStake { - fmt.Println("--") return Accept } From 57e15827b6d4b73488342129e28f492cbc03dce2 Mon Sep 17 00:00:00 2001 From: iowar Date: Sat, 30 Sep 2023 17:20:18 +0300 Subject: [PATCH 6/8] reject s<>s connections --- pkg/p2p/libp2p/conngater.go | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/pkg/p2p/libp2p/conngater.go b/pkg/p2p/libp2p/conngater.go index 598524ea..9b1810d7 100644 --- a/pkg/p2p/libp2p/conngater.go +++ b/pkg/p2p/libp2p/conngater.go @@ -103,23 +103,15 @@ func (cg *connectionGater) checkPeerStake(p peer.ID) connectionAllowance { enoughStake := stake.Cmp(cg.minimumStake) >= 0 - // s<>b connection - if (cg.selfType == p2p.PeerTypeSearcher) && enoughStake { - return Accept - } - - // b<>b connection - if (cg.selfType == p2p.PeerTypeBuilder) && enoughStake { - return Accept - } - + // possible s<>s connection // ! s<>s connection if (cg.selfType == p2p.PeerTypeSearcher) && !enoughStake { return DenySearcherToSearcher } - // deny the connection if the stake is not enough. - return DenyBlockedPeer + // Reject potential s<>s connections and accept the remaining requests, + // allowing authentication during the handshake phase + return Accept } // resolveConnectionAllowance resolves the connection allowance based on trusted and blocked statuses From d65735fa43843c533946471b5a672ccf35577789 Mon Sep 17 00:00:00 2001 From: iowar Date: Sun, 1 Oct 2023 10:10:53 +0300 Subject: [PATCH 7/8] fixed --- pkg/p2p/libp2p/conngater.go | 38 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/pkg/p2p/libp2p/conngater.go b/pkg/p2p/libp2p/conngater.go index 9b1810d7..dfd45208 100644 --- a/pkg/p2p/libp2p/conngater.go +++ b/pkg/p2p/libp2p/conngater.go @@ -23,15 +23,15 @@ const ( Accept ) -var connectionAllowanceStrings = map[connectionAllowance]string{ - Undecided: "Undecided", - DenyUnresolvedAddress: "DenyUnresolvedAddress", - DenyBadRegisterCall: "DenyBadRegisterCall", - DenyBlockedPeer: "DenyBlockedPeer", - DenyNotEnoughStake: "DenyNotEnoughStake", - DenySearcherToSearcher: "DenySearcherToSearcher", - Accept: "Allow", -} +//var connectionAllowanceStrings = map[connectionAllowance]string{ +// Undecided: "Undecided", +// DenyUnresolvedAddress: "DenyUnresolvedAddress", +// DenyBadRegisterCall: "DenyBadRegisterCall", +// DenyBlockedPeer: "DenyBlockedPeer", +// DenyNotEnoughStake: "DenyNotEnoughStake", +// DenySearcherToSearcher: "DenySearcherToSearcher", +// Accept: "Allow", +//} func (c connectionAllowance) isDeny() bool { return !(c == Accept || c == Undecided) @@ -149,11 +149,7 @@ func (cg *connectionGater) InterceptPeerDial(p peer.ID) bool { // TODO rate limiter func (cg *connectionGater) InterceptAddrDial(p peer.ID, addr multiaddr.Multiaddr) bool { allowance := cg.checkAllowedPeer(p) - if allowance.isDeny() { - return false - } - - return true + return !allowance.isDeny() } // InterceptAccept intercepts the process of accepting a connection @@ -179,8 +175,6 @@ func (cg *connectionGater) InterceptSecured(dir network.Direction, p peer.ID, co } else { return cg.validateOutboundConnection(p, connMultiaddrs) } - - return true } // InterceptUpgraded intercepts the process of upgrading a connection @@ -198,11 +192,7 @@ func (cg *connectionGater) validateInboundConnection(p peer.ID, connMultiaddrs n //cg.metrics.IncomingConnectionCount.Inc() allowance := cg.checkPeerStake(p) - if allowance.isDeny() { - return false - } - - return true + return !allowance.isDeny() } // validateOutboundConnection validates an outbound connection by extracting @@ -213,9 +203,5 @@ func (cg *connectionGater) validateOutboundConnection(p peer.ID, connMultiaddrs //cg.metrics.OutgoingConnectionCount.Inc() allowance := cg.checkPeerStake(p) - if allowance.isDeny() { - return false - } - - return true + return !allowance.isDeny() } From 8da92435a242fa80b3ae9c88e30092bf0525e3e2 Mon Sep 17 00:00:00 2001 From: iowar Date: Mon, 2 Oct 2023 12:57:27 +0300 Subject: [PATCH 8/8] fixed logger --- pkg/p2p/libp2p/libp2p.go | 5 +---- pkg/topology/topology.go | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/pkg/p2p/libp2p/libp2p.go b/pkg/p2p/libp2p/libp2p.go index 6df1e54c..40126b4a 100644 --- a/pkg/p2p/libp2p/libp2p.go +++ b/pkg/p2p/libp2p/libp2p.go @@ -105,10 +105,7 @@ func New(opts *Options) (*Service, error) { } for _, addr := range host.Addrs() { - opts.Logger.With( - "addr", addr, - "host", host.ID().Pretty(), - ).Info("p2p address") + opts.Logger.Info("p2p address", "addr", addr, "host_address", host.ID().Pretty()) } ethAddress, err := GetEthAddressFromPeerID(host.ID()) diff --git a/pkg/topology/topology.go b/pkg/topology/topology.go index 40ab6023..632c31f8 100644 --- a/pkg/topology/topology.go +++ b/pkg/topology/topology.go @@ -96,7 +96,7 @@ func (t *topology) Disconnected(p p2p.Peer) { t.mu.Lock() defer t.mu.Unlock() - t.logger.With("peer", p).Info("disconnected") + t.logger.Info("disconnected", "peer", p) switch p.Type { case p2p.PeerTypeBuilder: