mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-04 02:53:45 +00:00
pss is now separate package pss event feed removed, multipile handlers allowed instead NOTE! pss tests are removed and will be rewritten remove pssclient outbox, psscache bug fix WIP tests reinstation
228 lines
5.4 KiB
Go
228 lines
5.4 KiB
Go
package pss
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
"sync/atomic"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/event"
|
|
"github.com/ethereum/go-ethereum/log"
|
|
"github.com/ethereum/go-ethereum/node"
|
|
"github.com/ethereum/go-ethereum/p2p"
|
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
|
"github.com/ethereum/go-ethereum/p2p/protocols"
|
|
"github.com/ethereum/go-ethereum/pot"
|
|
"github.com/ethereum/go-ethereum/rpc"
|
|
)
|
|
|
|
const (
|
|
inboxCapacity = 3000
|
|
outboxCapacity = 100
|
|
addrLen = common.HashLength
|
|
)
|
|
|
|
// implements p2p.Server
|
|
// implements net.Conn
|
|
type PssClient struct {
|
|
localuri string
|
|
remoteuri string
|
|
ctx context.Context
|
|
cancel func()
|
|
subscription *rpc.ClientSubscription
|
|
topicsC chan []byte
|
|
msgC chan PssAPIMsg
|
|
quitC chan struct{}
|
|
quitting uint32
|
|
ws *rpc.Client
|
|
lock sync.Mutex
|
|
peerPool map[PssTopic]map[pot.Address]*pssRPCRW
|
|
protos []*p2p.Protocol
|
|
}
|
|
|
|
type pssRPCRW struct {
|
|
*PssClient
|
|
topic *PssTopic
|
|
spec *protocols.Spec
|
|
msgC chan []byte
|
|
addr pot.Address
|
|
}
|
|
|
|
func (self *PssClient) newpssRPCRW(addr pot.Address, spec *protocols.Spec, topic *PssTopic) *pssRPCRW {
|
|
return &pssRPCRW {
|
|
PssClient: self,
|
|
topic: topic,
|
|
spec: spec,
|
|
msgC: make(chan []byte),
|
|
addr: addr,
|
|
}
|
|
}
|
|
|
|
func (rw *pssRPCRW) ReadMsg() (p2p.Msg, error) {
|
|
msg := <- rw.msgC
|
|
log.Warn("pssrpcrw read", "msg", msg)
|
|
pmsg, err := ToP2pMsg(msg)
|
|
if err != nil {
|
|
return p2p.Msg{}, err
|
|
}
|
|
|
|
return pmsg, nil
|
|
}
|
|
|
|
func (rw *pssRPCRW) WriteMsg(msg p2p.Msg) error {
|
|
|
|
ifc, found := rw.spec.NewMsg(msg.Code)
|
|
if !found {
|
|
return fmt.Errorf("could not find interface for msg #%d", msg.Code)
|
|
}
|
|
msg.Decode(ifc)
|
|
pmsg, err := newProtocolMsg(msg.Code, ifc)
|
|
if err != nil {
|
|
return fmt.Errorf("Could not render protocolmessage", "error", err)
|
|
}
|
|
|
|
return rw.PssClient.ws.CallContext(rw.PssClient.ctx, nil, "pss_sendRaw", rw.topic, PssAPIMsg{
|
|
Addr: rw.addr.Bytes(),
|
|
Msg: pmsg,
|
|
})
|
|
|
|
}
|
|
|
|
// remotehost: hostname of node running websockets proxy to pss (default localhost)
|
|
// remoteport: port of node running websockets proxy to pss (0 = go-ethereum node default)
|
|
// secure: whether or not to use secure connection
|
|
// originhost: local if host to connect from
|
|
|
|
func NewPssClient(ctx context.Context, cancel func(), remotehost string, remoteport int, secure bool, originhost string) *PssClient {
|
|
prefix := "ws"
|
|
|
|
if ctx == nil {
|
|
ctx = context.Background()
|
|
cancel = func() {return}
|
|
}
|
|
pssc := &PssClient{
|
|
msgC: make(chan PssAPIMsg),
|
|
quitC: make(chan struct{}),
|
|
peerPool: make(map[PssTopic]map[pot.Address]*pssRPCRW),
|
|
ctx: ctx,
|
|
cancel: cancel,
|
|
}
|
|
|
|
if remotehost == "" {
|
|
remotehost = "localhost"
|
|
}
|
|
|
|
if remoteport == 0 {
|
|
remoteport = node.DefaultWSPort
|
|
}
|
|
|
|
if originhost == "" {
|
|
originhost = "localhost"
|
|
}
|
|
|
|
if secure {
|
|
prefix = "wss"
|
|
}
|
|
|
|
pssc.remoteuri = fmt.Sprintf("%s://%s:%d", prefix, remotehost, remoteport)
|
|
pssc.localuri = fmt.Sprintf("%s://%s", prefix, originhost)
|
|
|
|
return pssc
|
|
}
|
|
|
|
func (self *PssClient) shutdown() {
|
|
atomic.StoreUint32(&self.quitting, 1)
|
|
self.cancel()
|
|
}
|
|
|
|
func (self *PssClient) Start() error {
|
|
log.Debug("Dialing ws", "src", self.localuri, "dst", self.remoteuri)
|
|
ws, err := rpc.DialWebsocket(self.ctx, self.remoteuri, self.localuri)
|
|
if err != nil {
|
|
return fmt.Errorf("Couldnt dial pss websocket: %v", err)
|
|
}
|
|
|
|
self.ws = ws
|
|
|
|
return nil
|
|
}
|
|
|
|
func (self *PssClient) RunProtocol(proto *p2p.Protocol, spec *protocols.Spec) error {
|
|
topic := NewTopic(spec.Name, int(spec.Version))
|
|
msgC := make(chan PssAPIMsg)
|
|
self.peerPool[topic] = make(map[pot.Address]*pssRPCRW)
|
|
sub, err := self.ws.Subscribe(self.ctx, "pss", msgC, "newMsg", topic)
|
|
if err != nil {
|
|
return fmt.Errorf("pss event subscription failed: %v", err)
|
|
}
|
|
|
|
self.subscription = sub
|
|
|
|
// dispatch incoming messages
|
|
go func() {
|
|
for {
|
|
select {
|
|
case msg := <- msgC:
|
|
var addr pot.Address
|
|
copy(addr[:], msg.Addr)
|
|
if self.peerPool[topic][addr] == nil {
|
|
self.peerPool[topic][addr] = self.newpssRPCRW(addr, spec, &topic)
|
|
nid, _ := discover.HexID("0x00")
|
|
p := p2p.NewPeer(nid, fmt.Sprintf("%v", addr), []p2p.Cap{})
|
|
go proto.Run(p, self.peerPool[topic][addr])
|
|
}
|
|
go func() {
|
|
self.peerPool[topic][addr].msgC <- msg.Msg
|
|
}()
|
|
case <-self.quitC:
|
|
self.shutdown()
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
self.protos = append(self.protos, proto)
|
|
return nil
|
|
}
|
|
|
|
func (self *PssClient) Stop() error {
|
|
self.cancel()
|
|
return nil
|
|
}
|
|
|
|
func (self *PssClient) AddPssPeer(addr pot.Address, spec *protocols.Spec) {
|
|
topic := NewTopic(spec.Name, int(spec.Version))
|
|
if self.peerPool[topic][addr] == nil {
|
|
self.peerPool[topic][addr] = self.newpssRPCRW(addr, spec, &topic)
|
|
}
|
|
}
|
|
|
|
func (self *PssClient) RemovePssPeer(addr pot.Address, spec *protocols.Spec) {
|
|
topic := NewTopic(spec.Name, int(spec.Version))
|
|
delete(self.peerPool[topic], addr)
|
|
}
|
|
|
|
func (self *PssClient) SubscribeEvents(ch chan *p2p.PeerEvent) event.Subscription {
|
|
log.Error("PSS client handles events internally, use the read functions instead")
|
|
return nil
|
|
}
|
|
|
|
func (self *PssClient) PeerCount() int {
|
|
return len(self.peerPool)
|
|
}
|
|
|
|
func (self *PssClient) NodeInfo() *p2p.NodeInfo {
|
|
return nil
|
|
}
|
|
|
|
func (self *PssClient) PeersInfo() []*p2p.PeerInfo {
|
|
return nil
|
|
}
|
|
func (self *PssClient) AddPeer(node *discover.Node) {
|
|
log.Error("Cannot add peer in PSS with discover.Node, need swarm overlay address")
|
|
}
|
|
|
|
func (self *PssClient) RemovePeer(node *discover.Node) {
|
|
log.Error("Cannot remove peer in PSS with discover.Node, need swarm overlay address")
|
|
}
|