mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
p2p/discv5: implement talkRequest
This commit is contained in:
parent
3bb6815fc1
commit
4bb4cb0fd4
3 changed files with 102 additions and 1 deletions
|
|
@ -22,12 +22,14 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/mclock"
|
"github.com/ethereum/go-ethereum/common/mclock"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
"github.com/ethereum/go-ethereum/p2p/netutil"
|
"github.com/ethereum/go-ethereum/p2p/netutil"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
|
|
@ -70,6 +72,11 @@ type Network struct {
|
||||||
topicRegisterReq chan topicRegisterReq
|
topicRegisterReq chan topicRegisterReq
|
||||||
topicSearchReq chan topicSearchReq
|
topicSearchReq chan topicSearchReq
|
||||||
|
|
||||||
|
talkRequestSubLock sync.RWMutex
|
||||||
|
talkResponseSubLock sync.Mutex
|
||||||
|
talkRequestSubs map[string]TalkRequestHandler
|
||||||
|
talkResponseSubs map[string]TalkResponseHandler
|
||||||
|
|
||||||
// State of the main loop.
|
// State of the main loop.
|
||||||
tab *Table
|
tab *Table
|
||||||
topictab *topicTable
|
topictab *topicTable
|
||||||
|
|
@ -79,6 +86,11 @@ type Network struct {
|
||||||
timeoutTimers map[timeoutEvent]*time.Timer
|
timeoutTimers map[timeoutEvent]*time.Timer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
TalkRequestHandler func(enode.ID, rlp.RawValue) (rlp.RawValue, bool)
|
||||||
|
TalkResponseHandler func(rlp.RawValue) bool
|
||||||
|
)
|
||||||
|
|
||||||
// transport is implemented by the UDP transport.
|
// transport is implemented by the UDP transport.
|
||||||
// it is an interface so we can test without opening lots of UDP
|
// it is an interface so we can test without opening lots of UDP
|
||||||
// sockets and without generating a private key.
|
// sockets and without generating a private key.
|
||||||
|
|
@ -155,6 +167,8 @@ func newNetwork(conn transport, ourPubkey ecdsa.PublicKey, dbPath string, netres
|
||||||
topicRegisterReq: make(chan topicRegisterReq),
|
topicRegisterReq: make(chan topicRegisterReq),
|
||||||
topicSearchReq: make(chan topicSearchReq),
|
topicSearchReq: make(chan topicSearchReq),
|
||||||
nodes: make(map[NodeID]*Node),
|
nodes: make(map[NodeID]*Node),
|
||||||
|
talkRequestSubs: make(map[string]TalkRequestHandler),
|
||||||
|
talkResponseSubs: make(map[string]TalkResponseHandler),
|
||||||
}
|
}
|
||||||
go net.loop()
|
go net.loop()
|
||||||
return net, nil
|
return net, nil
|
||||||
|
|
@ -772,6 +786,7 @@ type nodeNetGuts struct {
|
||||||
deferredQueries []*findnodeQuery // queries that can't be sent yet
|
deferredQueries []*findnodeQuery // queries that can't be sent yet
|
||||||
pendingNeighbours *findnodeQuery // current query, waiting for reply
|
pendingNeighbours *findnodeQuery // current query, waiting for reply
|
||||||
queryTimeouts int
|
queryTimeouts int
|
||||||
|
talkFailures int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *nodeNetGuts) deferQuery(q *findnodeQuery) {
|
func (n *nodeNetGuts) deferQuery(q *findnodeQuery) {
|
||||||
|
|
@ -828,6 +843,8 @@ const (
|
||||||
topicRegisterPacket
|
topicRegisterPacket
|
||||||
topicQueryPacket
|
topicQueryPacket
|
||||||
topicNodesPacket
|
topicNodesPacket
|
||||||
|
talkRequestPacket
|
||||||
|
talkResponsePacket
|
||||||
|
|
||||||
// Non-packet events.
|
// Non-packet events.
|
||||||
// Event values in this category are allocated outside
|
// Event values in this category are allocated outside
|
||||||
|
|
@ -835,6 +852,7 @@ const (
|
||||||
pongTimeout nodeEvent = iota + 256
|
pongTimeout nodeEvent = iota + 256
|
||||||
pingTimeout
|
pingTimeout
|
||||||
neighboursTimeout
|
neighboursTimeout
|
||||||
|
talkTimeout
|
||||||
)
|
)
|
||||||
|
|
||||||
// Node State Machine.
|
// Node State Machine.
|
||||||
|
|
@ -1196,7 +1214,51 @@ func (net *Network) handleQueryEvent(n *Node, ev nodeEvent, pkt *ingressPacket)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return n.state, nil
|
return n.state, nil
|
||||||
|
case talkRequestPacket:
|
||||||
|
p := pkt.data.(*talkRequest)
|
||||||
|
net.talkRequestSubLock.RLock()
|
||||||
|
subFn := net.talkRequestSubs[string(p.TalkID)]
|
||||||
|
net.talkRequestSubLock.RUnlock()
|
||||||
|
if subFn != nil {
|
||||||
|
resp, ok := subFn(enode.ID(n.sha), p.Payload)
|
||||||
|
if ok {
|
||||||
|
net.conn.send(n, talkResponsePacket, talkResponse{ReplyTok: pkt.hash, Payload: resp})
|
||||||
|
} else {
|
||||||
|
n.talkFailures++
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
n.talkFailures++
|
||||||
|
}
|
||||||
|
if n.talkFailures > maxTalkFailures && n.state == known {
|
||||||
|
return contested, errors.New("too many talk failures")
|
||||||
|
}
|
||||||
|
return n.state, nil
|
||||||
|
case talkResponsePacket:
|
||||||
|
p := pkt.data.(*talkResponse)
|
||||||
|
net.talkResponseSubLock.Lock()
|
||||||
|
key := string(n.sha[:]) + string(p.ReplyTok)
|
||||||
|
subFn := net.talkResponseSubs[key]
|
||||||
|
if subFn != nil {
|
||||||
|
delete(net.talkResponseSubs, key)
|
||||||
|
}
|
||||||
|
net.talkResponseSubLock.Unlock()
|
||||||
|
if subFn == nil || !subFn(p.Payload) {
|
||||||
|
n.talkFailures++
|
||||||
|
if n.talkFailures > maxTalkFailures && n.state == known {
|
||||||
|
return contested, errors.New("too many talk failures")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n.state, nil
|
||||||
|
case talkTimeout:
|
||||||
|
if n.pendingNeighbours != nil {
|
||||||
|
n.pendingNeighbours.reply <- nil
|
||||||
|
n.pendingNeighbours = nil
|
||||||
|
}
|
||||||
|
n.queryTimeouts++
|
||||||
|
if n.queryTimeouts > maxFindnodeFailures && n.state == known {
|
||||||
|
return contested, errors.New("too many timeouts")
|
||||||
|
}
|
||||||
|
return n.state, nil
|
||||||
default:
|
default:
|
||||||
return n.state, errInvalidEvent
|
return n.state, errInvalidEvent
|
||||||
}
|
}
|
||||||
|
|
@ -1260,3 +1322,27 @@ func (net *Network) handleNeighboursPacket(n *Node, pkt *ingressPacket) error {
|
||||||
n.startNextQuery(net)
|
n.startNextQuery(net)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (net *Network) RegisterTalkHandler(talkID string, handler TalkRequestHandler) {
|
||||||
|
net.talkRequestSubLock.Lock()
|
||||||
|
net.talkRequestSubs[talkID] = handler
|
||||||
|
net.talkRequestSubLock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (net *Network) SendTalkRequest(to *enode.Node, talkID string, payload rlp.RawValue, handler TalkResponseHandler) func() bool {
|
||||||
|
node := NewNode(to.ID(), to.IP(), to.UDP(), to.TCP())
|
||||||
|
net.talkResponseSubLock.Lock()
|
||||||
|
hash := net.conn.send(node, talkRequestPacket, talkRequest{TalkID: []byte(talkID), Payload: payload})
|
||||||
|
key := string(to.sha[:]) + string(hash[:])
|
||||||
|
net.talkResponseSubs[key] = handler
|
||||||
|
net.talkResponseSubLock.Unlock()
|
||||||
|
return func() bool {
|
||||||
|
net.talkResponseSubLock.Lock()
|
||||||
|
cancel := net.talkResponseSubs[key] != nil
|
||||||
|
if cancel {
|
||||||
|
delete(net.talkResponseSubs, key)
|
||||||
|
}
|
||||||
|
net.talkResponseSubLock.Unlock()
|
||||||
|
return cancel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ const (
|
||||||
nBuckets = hashBits + 1 // Number of buckets
|
nBuckets = hashBits + 1 // Number of buckets
|
||||||
|
|
||||||
maxFindnodeFailures = 5
|
maxFindnodeFailures = 5
|
||||||
|
maxTalkFailures = 5
|
||||||
)
|
)
|
||||||
|
|
||||||
type Table struct {
|
type Table struct {
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,16 @@ type (
|
||||||
Nodes []rpcNode
|
Nodes []rpcNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
talkRequest struct {
|
||||||
|
TalkID []byte
|
||||||
|
Payload rlp.RawValue
|
||||||
|
}
|
||||||
|
|
||||||
|
talkResponse struct {
|
||||||
|
ReplyTok []byte
|
||||||
|
Payload rlp.RawValue
|
||||||
|
}
|
||||||
|
|
||||||
rpcNode struct {
|
rpcNode struct {
|
||||||
IP net.IP // len 4 for IPv4 or 16 for IPv6
|
IP net.IP // len 4 for IPv4 or 16 for IPv6
|
||||||
UDP uint16 // for discovery protocol
|
UDP uint16 // for discovery protocol
|
||||||
|
|
@ -420,6 +430,10 @@ func decodePacket(buffer []byte, pkt *ingressPacket) error {
|
||||||
pkt.data = new(topicQuery)
|
pkt.data = new(topicQuery)
|
||||||
case topicNodesPacket:
|
case topicNodesPacket:
|
||||||
pkt.data = new(topicNodes)
|
pkt.data = new(topicNodes)
|
||||||
|
case talkRequestPacket:
|
||||||
|
pkt.data = new(talkRequest)
|
||||||
|
case talkResponsePacket:
|
||||||
|
pkt.data = new(talkResponse)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unknown packet type: %d", sigdata[0])
|
return fmt.Errorf("unknown packet type: %d", sigdata[0])
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue