arnaucube
arnaucube/go-dvotePublic Self-hosted repository
go-dvote/net/swarm/swarm.go
net/swarm/swarm.goRaw
  1package swarm
  2
  3import (
  4	"context"
  5	"crypto/ecdsa"
  6	"fmt"
  7	"os"
  8	"os/user"
  9	"time"
 10
 11	"github.com/ethereum/go-ethereum/common/hexutil"
 12	"github.com/ethereum/go-ethereum/node"
 13
 14	"github.com/ethereum/go-ethereum/p2p"
 15
 16	"github.com/ethereum/go-ethereum/log"
 17	"github.com/ethereum/go-ethereum/p2p/enode"
 18	"github.com/ethereum/go-ethereum/swarm"
 19
 20	swarmapi "github.com/ethereum/go-ethereum/swarm/api"
 21	"github.com/ethereum/go-ethereum/swarm/network"
 22	"github.com/ethereum/go-ethereum/swarm/pss"
 23)
 24
 25const (
 26	// MaxPeers is the maximum number of p2p peer connections
 27	MaxPeers = 10
 28)
 29
 30// SwarmBootnodes list of bootnodes for the SWARM network
 31var SwarmBootnodes = []string{
 32	// EF Swarm Bootnode - AWS - eu-central-1
 33	"enode://4c113504601930bf2000c29bcd98d1716b6167749f58bad703bae338332fe93cc9d9204f08afb44100dc7bea479205f5d162df579f9a8f76f8b402d339709023@3.122.203.99:30301",
 34	// EF Swarm Bootnode - AWS - us-west-2
 35	"enode://89f2ede3371bff1ad9f2088f2012984e280287a4e2b68007c2a6ad994909c51886b4a8e9e2ecc97f9910aca538398e0a5804b0ee80a187fde1ba4f32626322ba@52.35.212.179:30301",
 36}
 37
 38func newNode(key *ecdsa.PrivateKey, port int, httpport int, wsport int,
 39	datadir string, modules ...string) (*node.Node, *node.Config, error) {
 40	if port == 0 {
 41		port = 30100
 42	}
 43	cfg := &node.DefaultConfig
 44	if key != nil {
 45		cfg.P2P.PrivateKey = key
 46	}
 47	cfg.P2P.MaxPeers = MaxPeers
 48	cfg.P2P.ListenAddr = fmt.Sprintf("0.0.0.0:%d", port)
 49	cfg.P2P.EnableMsgEvents = true
 50	cfg.P2P.NoDiscovery = false
 51	cfg.P2P.DiscoveryV5 = true
 52	cfg.IPCPath = datadir + "/node.ipc"
 53	cfg.DataDir = datadir
 54	if httpport > 0 {
 55		cfg.HTTPHost = node.DefaultHTTPHost
 56		cfg.HTTPPort = httpport
 57		cfg.HTTPCors = []string{"*"}
 58	}
 59	if wsport > 0 {
 60		cfg.WSHost = node.DefaultWSHost
 61		cfg.WSPort = wsport
 62		cfg.WSOrigins = []string{"*"}
 63		for i := 0; i < len(modules); i++ {
 64			cfg.WSModules = append(cfg.WSModules, modules[i])
 65		}
 66	}
 67	stack, err := node.New(cfg)
 68	if err != nil {
 69		return nil, nil, fmt.Errorf("ServiceNode create fail: %v", err)
 70	}
 71	return stack, cfg, nil
 72}
 73
 74func newSwarm(privkey *ecdsa.PrivateKey, datadir string, port int) (*swarm.Swarm, *swarmapi.Config, node.ServiceConstructor) {
 75	// create swarm service
 76	swarmCfg := swarmapi.NewConfig()
 77	swarmCfg.SyncEnabled = true
 78	swarmCfg.Port = fmt.Sprintf("%d", port)
 79	swarmCfg.Path = datadir
 80	swarmCfg.HiveParams.Discovery = true
 81	swarmCfg.Discovery = true
 82	swarmCfg.Pss.MsgTTL = time.Second * 10
 83	swarmCfg.Pss.CacheTTL = time.Second * 30
 84	swarmCfg.Pss.AllowRaw = true
 85	swarmCfg.Init(privkey)
 86	swarmNode, err := swarm.NewSwarm(swarmCfg, nil)
 87	if err != nil {
 88		log.Crit("cannot crate swarm node")
 89	}
 90	// register swarm service to the node
 91	var swarmService node.ServiceConstructor = func(ctx *node.ServiceContext) (node.Service, error) {
 92		//return swarm.NewSwarm(swarmCfg, nil)
 93		return swarmNode, nil
 94	}
 95	return swarmNode, swarmCfg, swarmService
 96}
 97
 98type swarmPorts struct {
 99	WebSockets int
100	HTTPRPC    int
101	Bzz        int
102	P2P        int
103}
104
105func NewSwarmPorts() *swarmPorts {
106	sp := new(swarmPorts)
107	sp.WebSockets = 8544
108	sp.HTTPRPC = 8543
109	sp.Bzz = 8542
110	sp.P2P = 31000
111	return sp
112}
113
114type SwarmNet struct {
115	Node       *node.Node
116	NodeConfig *node.Config
117	EnodeID    string
118	Datadir    string
119	Key        *ecdsa.PrivateKey
120	Pss        *pss.API
121	PssAddr    pss.PssAddress
122	Hive       *network.Hive
123	Ports      *swarmPorts
124}
125
126func (sn *SwarmNet) SetLog() {
127	// ensure good log formats for terminal
128	// handle verbosity flag
129	hs := log.StreamHandler(os.Stderr, log.TerminalFormat(true))
130	loglevel := log.LvlInfo
131	hf := log.LvlFilterHandler(loglevel, hs)
132	h := log.CallerFileHandler(hf)
133	log.Root().SetHandler(h)
134}
135
136func (sn *SwarmNet) PrintStats() {
137	// statistics thread
138	go func() {
139		for {
140			if sn.Node.Server() != nil && sn.Hive != nil {
141				addr := fmt.Sprintf("%x", sn.PssAddr)
142				var addrs [][]byte
143				addrs = append(addrs, []byte(addr))
144				peerCount := sn.Node.Server().PeerCount()
145				log.Info(fmt.Sprintf("PeerCount:%d NeighDepth:%d", peerCount, sn.Hive.NeighbourhoodDepth))
146			}
147			time.Sleep(time.Second * 5)
148		}
149	}()
150}
151
152func (sn *SwarmNet) SetDatadir(datadir string) {
153	sn.Datadir = datadir
154}
155
156func (sn *SwarmNet) SetKey(key *ecdsa.PrivateKey) {
157	sn.Key = key
158}
159
160func (sn *SwarmNet) Init() error {
161	var err error
162	if len(sn.Datadir) < 1 {
163		usr, err := user.Current()
164		if err != nil {
165			return err
166		}
167		sn.Datadir = usr.HomeDir + "/.dvote/swarm"
168		os.MkdirAll(sn.Datadir, 0755)
169	}
170
171	sn.SetLog()
172	sn.Ports = NewSwarmPorts()
173
174	// create node
175	sn.Node, sn.NodeConfig, err = newNode(sn.Key, sn.Ports.P2P,
176		sn.Ports.HTTPRPC, sn.Ports.WebSockets, sn.Datadir, "pss")
177	if err != nil {
178		return err
179	}
180	// set node key, if not set use the storage one or generate it
181	if sn.Key == nil {
182		sn.Key = sn.NodeConfig.NodeKey()
183	}
184
185	// create and register Swarm service
186	swarmNode, _, swarmHandler := newSwarm(sn.Key, sn.Datadir, sn.Ports.Bzz)
187	err = sn.Node.Register(swarmHandler)
188	if err != nil {
189		return fmt.Errorf("swarm register fail %v", err)
190	}
191
192	// start the node
193	sn.Node.Start()
194	for _, url := range SwarmBootnodes {
195		log.Info("Add bootnode " + url)
196		node, _ := enode.ParseV4(url)
197		sn.Node.Server().AddPeer(node)
198	}
199	//defer sn.Node.Stop()
200
201	_, cancel := context.WithTimeout(context.Background(), time.Second)
202	defer cancel()
203	time.Sleep(time.Second * 5)
204
205	// Get the services API
206	for _, a := range swarmNode.APIs() {
207		switch a.Service.(type) {
208		case *network.Hive:
209			sn.Hive = a.Service.(*network.Hive)
210		case *pss.API:
211			sn.Pss = a.Service.(*pss.API)
212		}
213	}
214
215	// Set the enode ID and the pss Address, fail if not available
216	sn.EnodeID = sn.Node.Server().NodeInfo().Enode
217
218	sn.PssAddr, err = sn.Pss.BaseAddr()
219	if err != nil {
220		return fmt.Errorf("pss API fail %v", err)
221	}
222	log.Info(fmt.Sprintf("My PSS address is %x", sn.PssAddr))
223
224	sn.PrintStats()
225
226	return nil
227}
228
229func (sn *SwarmNet) Test() error {
230	topic := pss.BytesToTopic([]byte("vocdoni_test"))
231	symKey := make([]byte, 32)
232	copy(symKey, []byte("vocdoni"))
233
234	var emptyAddress pss.PssAddress
235	emptyAddress = []byte("")
236	symKeyId, err := sn.Pss.SetSymmetricKey(symKey, topic, emptyAddress, true)
237	if err != nil {
238		fmt.Errorf("pss cannot set symkey %v", err)
239	}
240	var pssHandler pss.HandlerFunc = func(msg []byte, peer *p2p.Peer, asym bool, keyid string) error {
241		log.Info("pss received", "msg", fmt.Sprintf("%s", msg), "from", fmt.Sprintf("%x", peer))
242		return nil
243	}
244	topicHandler := pss.NewHandler(pssHandler)
245	topicUnregister := sn.Pss.Register(&topic, topicHandler)
246	defer topicUnregister()
247	log.Info(fmt.Sprintf("Subscribed to topic %s", topic.String()))
248
249	hostname, _ := os.Hostname()
250	for {
251		err = sn.Pss.SendSym(symKeyId, topic, hexutil.Bytes(fmt.Sprintf("Hello world from %s", hostname)))
252		/*	err = pssCli.SendRaw(emptyAddress, topic, []byte("Hello world!"))
253			if err != nil {
254				log.Warn("pss cannot send raw", "err", err)
255			}
256		*/
257		log.Info("pss sent", "err", err)
258		time.Sleep(10 * time.Second)
259	}
260}