From 26d7ceee1f33f40bc869f53f7ae9110834d51e9b Mon Sep 17 00:00:00 2001 From: nolash Date: Fri, 9 Jun 2017 01:13:43 +0200 Subject: [PATCH] swarm, swarm/network, swarm/pss: debug addr types + pss over devp2p --- swarm/network/protocol.go | 37 ++- swarm/pss/client/client.go | 4 + swarm/pss/protocols/chat/protocol.go | 98 ++++++ swarm/pss/pss.go | 43 ++- swarm/pss/pss_test.go | 4 +- swarm/swarm.go | 18 +- swarm/swarm_psschat.go | 428 +++++++++++++++++++++++++++ 7 files changed, 606 insertions(+), 26 deletions(-) create mode 100644 swarm/pss/protocols/chat/protocol.go create mode 100644 swarm/swarm_psschat.go diff --git a/swarm/network/protocol.go b/swarm/network/protocol.go index 8e9bb4f595..8243729100 100644 --- a/swarm/network/protocol.go +++ b/swarm/network/protocol.go @@ -23,6 +23,7 @@ import ( "net" "sync" "time" + "strings" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" @@ -113,6 +114,14 @@ func NewBzz(config *BzzConfig, kad Overlay, store StateStore) *Bzz { } } +func (b *Bzz) UpdateLocalAddr(byteaddr []byte) *bzzAddr { + b.localAddr.Update(&bzzAddr{ + UAddr: byteaddr, + OAddr: b.localAddr.OAddr, + }) + return b.localAddr +} + // Bzz implements the node.Service interface, offers Protocols // * handshake/hive // * discovery @@ -221,12 +230,12 @@ type bzzPeer struct { lastActive time.Time // time is updated whenever mutexes are releasing } -func newBzzPeer(p *protocols.Peer, over, under []byte) *bzzPeer { - return &bzzPeer{ - Peer: p, - localAddr: &bzzAddr{over, under}, - } -} +//func newBzzPeer(p *protocols.Peer, over, under []byte) *bzzPeer { +// return &bzzPeer{ +// Peer: p, +// localAddr: &bzzAddr{over, under}, +// } +//} // Off returns the overlay peer record for offline persistance func (self *bzzPeer) Off() OverlayAddr { @@ -283,6 +292,22 @@ func (self *bzzHandshake) Perform(p *p2p.Peer, rw p2p.MsgReadWriter) (err error) return fmt.Errorf("version mismatch %d (!= %d)", rhs.Version, self.Version) } self.peerAddr = rhs.Addr + peerid := p.ID() + log.Warn( + strings.Join( + []string{ + "handshake ok:", + fmt.Sprintf("p2p.Peer.ID(): ...... %v", p.ID()), + fmt.Sprintf("peerAddr.UAddr: ...... %x", self.peerAddr.UAddr[:32]), + fmt.Sprintf("peerAddr.OAddr: ...... %x", self.peerAddr.OAddr[:32]), + fmt.Sprintf("selfAddr.UAddr: ...... %x", self.Addr.UAddr[:32]), + fmt.Sprintf("selfAddr.OAddr: ...... %x", self.Addr.OAddr[:32]), + fmt.Sprintf("ToOverlayAddr(p2p.Peer.ID): .... %x", ToOverlayAddr(peerid[:])), + fmt.Sprintf("ToOverlayAddr(peerAddr.UAddr): .. %x", ToOverlayAddr(self.peerAddr.UAddr)), + }, "\n", + ), + ) + return nil } diff --git a/swarm/pss/client/client.go b/swarm/pss/client/client.go index a9bef6d3db..335316d3b2 100644 --- a/swarm/pss/client/client.go +++ b/swarm/pss/client/client.go @@ -207,6 +207,10 @@ func (self *Client) Stop() error { func (self *Client) AddPssPeer(addr pot.Address, spec *protocols.Spec) { topic := pss.NewTopic(spec.Name, int(spec.Version)) + if self.peerPool[topic] == nil { + log.Error("addpeer on unset topic") + return + } if self.peerPool[topic][addr] == nil { self.peerPool[topic][addr] = self.newpssRPCRW(addr, &topic) nid, _ := discover.HexID("0x00") diff --git a/swarm/pss/protocols/chat/protocol.go b/swarm/pss/protocols/chat/protocol.go new file mode 100644 index 0000000000..a6badc66e8 --- /dev/null +++ b/swarm/pss/protocols/chat/protocol.go @@ -0,0 +1,98 @@ +package chat + +import ( + "time" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/protocols" + "github.com/ethereum/go-ethereum/swarm/pss" + "github.com/ethereum/go-ethereum/swarm/network" +) + +const ( + ESendFail = iota +) + +var ( + chatConnString = map[int]string{ + ESendFail: "Send error", + } +) + +type ChatMsg struct { + Serial uint64 + Content []byte + Source string +} + +type chatPing struct { + Created time.Time + Pong bool +} + +type chatAck struct { + Seen time.Time + Serial uint64 +} + +var ChatProtocol = &protocols.Spec{ + Name: "pssChat", + Version: 1, + MaxMsgSize: 1024, + Messages: []interface{}{ + ChatMsg{}, chatPing{}, chatAck{}, + }, +} + +var ChatTopic = pss.NewTopic(ChatProtocol.Name, int(ChatProtocol.Version)) + +type ChatConn struct { + Addr []byte + E int +} + +func (c* ChatConn) Error() string { + return chatConnString[c.E] +} + +type ChatCtrl struct { + Peer *protocols.Peer + OutC chan interface{} + ConnC chan ChatConn + inC chan *ChatMsg + oAddr []byte + pingTX int + pingRX int + pingLast int +} + +func (self *ChatCtrl) chatHandler(msg interface{}) error { + Chatmsg, ok := msg.(*ChatMsg) + if ok { + if self.inC != nil { + self.inC <- Chatmsg + } + } + return nil +} + +func New(inC chan *ChatMsg, connC chan ChatConn, injectfunc func(*ChatCtrl)) *p2p.Protocol { +//func New(inC chan *ChatMsg, outC chan interface{}, connC chan ChatConn) *p2p.Protocol { + chatctrl := &ChatCtrl{ + inC: inC, + ConnC: connC, + } + return &p2p.Protocol{ + Name: ChatProtocol.Name, + Version: ChatProtocol.Version, + Length: 3, + Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error { + peerid := p.ID() + pp := protocols.NewPeer(p, rw, ChatProtocol) + chatctrl.Peer = pp + chatctrl.oAddr = network.ToOverlayAddr(peerid[:]) + injectfunc(chatctrl) + pp.Run(chatctrl.chatHandler) + return nil + }, + } +} diff --git a/swarm/pss/pss.go b/swarm/pss/pss.go index 9ac35d9f47..2f82c9c42b 100644 --- a/swarm/pss/pss.go +++ b/swarm/pss/pss.go @@ -32,6 +32,7 @@ var ( ) type senderPeer interface { + ID() discover.NodeID Address() []byte Send(interface{}) error } @@ -69,7 +70,8 @@ type pssDigest [digestLength]byte type Pss struct { network.Overlay // we can get the overlayaddress from this peerPool map[pot.Address]map[Topic]p2p.MsgReadWriter // keep track of all virtual p2p.Peers we are currently speaking to - fwdPool map[pot.Address]*protocols.Peer // keep track of all peers sitting on the pssmsg routing layer + //fwdPool map[pot.Address]*protocols.Peer // keep track of all peers sitting on the pssmsg routing layer + fwdPool map[discover.NodeID]*protocols.Peer // keep track of all peers sitting on the pssmsg routing layer handlers map[Topic]map[*Handler]bool // topic and version based pss payload handlers fwdcache map[pssDigest]pssCacheEntry // checksum of unique fields from pssmsg mapped to expiry, cache to determine whether to drop msg cachettl time.Duration // how long to keep messages in fwdcache @@ -98,7 +100,8 @@ func NewPss(k network.Overlay, dpa *storage.DPA, params *PssParams) *Pss { return &Pss{ Overlay: k, peerPool: make(map[pot.Address]map[Topic]p2p.MsgReadWriter, PssPeerCapacity), - fwdPool: make(map[pot.Address]*protocols.Peer), + //fwdPool: make(map[pot.Address]*protocols.Peer), + fwdPool: make(map[discover.NodeID]*protocols.Peer), handlers: make(map[Topic]map[*Handler]bool), fwdcache: make(map[pssDigest]pssCacheEntry), cachettl: params.Cachettl, @@ -132,9 +135,11 @@ func (self *Pss) Protocols() []p2p.Protocol { func (self *Pss) Run(p *p2p.Peer, rw p2p.MsgReadWriter) error { pp := protocols.NewPeer(p, rw, pssSpec) - id := p.ID() - a := pot.NewAddressFromBytes(network.ToOverlayAddr(id[:])) - self.fwdPool[a] = pp + //addr := network.NewAddrFromNodeID(id) + //potaddr := pot.NewHashAddressFromBytes(addr.OAddr) + //self.fwdPool[potaddr.Address] = pp + self.fwdPool[p.ID()] = pp + return pp.Run(self.handlePssMsg) } @@ -315,15 +320,21 @@ func (self *Pss) Forward(msg *PssMsg) error { // send with kademlia // find the closest peer to the recipient and attempt to send self.Overlay.EachConn(msg.To, 256, func(op network.OverlayConn, po int, isproxbin bool) bool { - a := pot.NewAddressFromBytes(op.Address()) - pp := self.fwdPool[a] - addr := self.Overlay.BaseAddr() - sendMsg := fmt.Sprintf("%x: msg to %x via %x", common.ByteLabel(addr), common.ByteLabel(msg.To), common.ByteLabel(op.Address())) + sp, ok := op.(senderPeer) + if !ok { + log.Crit("Pss cannot use kademlia peer type") + return false + } + sendMsg := fmt.Sprintf("TO %x FROM %x VIA %x", common.ByteLabel(msg.To), common.ByteLabel(self.BaseAddr()), common.ByteLabel(op.Address())) + //h := pot.NewHashAddressFromBytes(op.Address()) + //pp := self.fwdPool[h.Address] + pp := self.fwdPool[sp.ID()] if self.checkFwdCache(op.Address(), digest) { - log.Info(fmt.Sprintf("%v: peer already forwarded to", sendMsg)) + log.Info("%v: peer already forwarded to", sendMsg) return true } err := pp.Send(msg) + //err := sp.Send(msg) if err != nil { log.Warn(fmt.Sprintf("%v: failed forwarding: %v", sendMsg, err)) return true @@ -416,7 +427,7 @@ func (prw PssReadWriter) ReadMsg() (p2p.Msg, error) { // Implements p2p.MsgWriter func (prw PssReadWriter) WriteMsg(msg p2p.Msg) error { - log.Warn("got writemsg pssclient", "msg", msg) + log.Trace("pssrw writemsg", "msg", msg) rlpdata := make([]byte, msg.Size) msg.Payload.Read(rlpdata) pmsg, err := rlp.EncodeToBytes(ProtocolMsg{ @@ -446,19 +457,18 @@ type PssProtocol struct { } // Constructor -func RegisterPssProtocol(ps *Pss, topic *Topic, spec *protocols.Spec, targetprotocol *p2p.Protocol) error { +func RegisterPssProtocol(ps *Pss, topic *Topic, spec *protocols.Spec, targetprotocol *p2p.Protocol) *PssProtocol { pp := &PssProtocol{ Pss: ps, proto: targetprotocol, topic: topic, spec: spec, } - ps.Register(topic, pp.handle) - return nil + return pp } -func (self *PssProtocol) handle(msg []byte, p *p2p.Peer, senderAddr []byte) error { - hashoaddr := pot.NewAddressFromBytes(senderAddr) +func (self *PssProtocol) Handle(msg []byte, p *p2p.Peer, senderAddr []byte) error { + hashoaddr := pot.NewHashAddressFromBytes(senderAddr).Address if !self.isActive(hashoaddr, *self.topic) { rw := &PssReadWriter{ Pss: self.Pss, @@ -480,3 +490,4 @@ func (self *PssProtocol) handle(msg []byte, p *p2p.Peer, senderAddr []byte) erro return nil } + diff --git a/swarm/pss/pss_test.go b/swarm/pss/pss_test.go index 3ee8af3116..3702868ebc 100644 --- a/swarm/pss/pss_test.go +++ b/swarm/pss/pss_test.go @@ -187,7 +187,7 @@ func TestSimpleLinear(t *testing.T) { C: make(chan struct{}), } - err = RegisterPssProtocol(ps, &PingTopic, PingProtocol, NewPingProtocol(ping.PingHandler)) + ps.Register(&PingTopic, RegisterPssProtocol(ps, &PingTopic, PingProtocol, NewPingProtocol(ping.PingHandler)).Handle) if err != nil { t.Fatalf("Failed to register virtual protocol in pss: %v", err) @@ -543,7 +543,7 @@ func newServices() adapters.Services { ping := &Ping{ C: make(chan struct{}), } - err = RegisterPssProtocol(ps, &PingTopic, PingProtocol, NewPingProtocol(ping.PingHandler)) + ps.Register(&PingTopic, RegisterPssProtocol(ps, &PingTopic, PingProtocol, NewPingProtocol(ping.PingHandler)).Handle) if err != nil { log.Error("Couldnt register pss protocol", "err", err) os.Exit(1) diff --git a/swarm/swarm.go b/swarm/swarm.go index 09260c634f..71334ba661 100644 --- a/swarm/swarm.go +++ b/swarm/swarm.go @@ -1,3 +1,5 @@ +// +build !psschat + // Copyright 2016 The go-ethereum Authors // This file is part of the go-ethereum library. // @@ -21,6 +23,7 @@ import ( "context" "crypto/ecdsa" "fmt" + "io/ioutil" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -106,6 +109,7 @@ func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, config *api. kp, ) + config.HiveParams.Discovery = true bzzconfig := &network.BzzConfig{ UnderlayAddr: common.FromHex(config.PublicKey), OverlayAddr: common.FromHex(config.BzzKey), @@ -129,10 +133,20 @@ func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, config *api. dpaChunkStore := storage.NewDpaChunkStore(self.lstore, self.storage) log.Debug(fmt.Sprintf("-> Local Access to Swarm")) - // Swarm Hash Merklised Chunking for Arbitrary-length Document/File storage + // Swarm Hash Merklised Chunking for Arbitrary-length Document/File storage self.dpa = storage.NewDPA(dpaChunkStore, self.config.ChunkerParams) log.Debug(fmt.Sprintf("-> Content Store API")) + // netstore is broken, temp workaround to fiddle with pss + cachedir, err := ioutil.TempDir("", "bzz-tmp") + if err != nil { + return nil, err + } + self.dpa, err = storage.NewLocalDPA(cachedir) + if err != nil { + return nil, err + } + // Pss = postal service over swarm (devp2p over bzz) if pssEnabled { pssparams := pss.NewPssParams(false) @@ -195,7 +209,7 @@ func (self *Swarm) Start(net *p2p.Server) error { log.Error("bzz failed", "err", err) return err } - log.Info(fmt.Sprintf("Swarm network started on bzz address: %v", self.bzz.Hive.Overlay.BaseAddr())) + log.Info(fmt.Sprintf("Swarm network started on bzz address: %x", self.bzz.Hive.Overlay.BaseAddr())) if self.pss != nil { self.pss.Start(net) diff --git a/swarm/swarm_psschat.go b/swarm/swarm_psschat.go new file mode 100644 index 0000000000..18d31b21c8 --- /dev/null +++ b/swarm/swarm_psschat.go @@ -0,0 +1,428 @@ +// +build psschat + +// Copyright 2016 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package swarm + +import ( + "bytes" + "context" + "crypto/ecdsa" + "fmt" + "io/ioutil" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/contracts/chequebook" + "github.com/ethereum/go-ethereum/contracts/ens" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/swarm/api" + httpapi "github.com/ethereum/go-ethereum/swarm/api/http" + "github.com/ethereum/go-ethereum/swarm/fuse" + "github.com/ethereum/go-ethereum/swarm/network" + "github.com/ethereum/go-ethereum/swarm/pss" + "github.com/ethereum/go-ethereum/swarm/storage" + psschat "github.com/ethereum/go-ethereum/swarm/pss/protocols/chat" +) + +// the swarm stack +type Swarm struct { + config *api.Config // swarm configuration + api *api.Api // high level api layer (fs/manifest) + dns api.Resolver // DNS registrar + storage storage.ChunkStore // internal access to storage, common interface to cloud storage backends + dpa *storage.DPA // distributed preimage archive, the local API to the storage with document level storage/retrieval support + cloud storage.CloudStore // procurement, cloud storage backend (can multi-cloud) + //hive *network.Hive // the logistic manager + bzz *network.Bzz // hive and bzz protocol + backend chequebook.Backend // simple blockchain Backend + privateKey *ecdsa.PrivateKey + corsString string + swapEnabled bool + lstore *storage.LocalStore // local store, needs to store for releasing resources after node stopped + sfs *fuse.SwarmFS // need this to cleanup all the active mounts on node exit + pss *pss.Pss +} + +type SwarmAPI struct { + Api *api.Api + Backend chequebook.Backend + PrvKey *ecdsa.PrivateKey +} + +func (self *Swarm) API() *SwarmAPI { + return &SwarmAPI{ + Api: self.api, + Backend: self.backend, + PrvKey: self.privateKey, + } +} + +// creates a new swarm service instance +// implements node.Service +func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, config *api.Config, swapEnabled, syncEnabled bool, cors string, pssEnabled bool) (self *Swarm, err error) { + if bytes.Equal(common.FromHex(config.PublicKey), storage.ZeroKey) { + return nil, fmt.Errorf("empty public key") + } + if bytes.Equal(common.FromHex(config.BzzKey), storage.ZeroKey) { + return nil, fmt.Errorf("empty bzz key") + } + + self = &Swarm{ + config: config, + swapEnabled: swapEnabled, + backend: backend, + privateKey: config.Swap.PrivateKey(), + corsString: cors, + } + log.Debug(fmt.Sprintf("Setting up Swarm service components")) + + hash := storage.MakeHashFunc(config.ChunkerParams.Hash) + self.lstore, err = storage.NewLocalStore(hash, config.StoreParams) + if err != nil { + return + } + + log.Debug("Set up local db access (iterator/counter)") + + kp := network.NewKadParams() + to := network.NewKademlia( + common.FromHex(config.BzzKey), + kp, + ) + + config.HiveParams.Discovery = true + + nodeid := discover.PubkeyID(crypto.ToECDSAPub(common.FromHex(config.PublicKey))) + addr := network.NewAddrFromNodeID(nodeid) + bzzconfig := &network.BzzConfig{ + OverlayAddr: common.FromHex(config.BzzKey), + UnderlayAddr: addr.UAddr, + HiveParams: config.HiveParams, + } + self.bzz = network.NewBzz(bzzconfig, to, nil) + + // set up the kademlia hive + // self.hive = network.NewHive( + // config.HiveParams, // configuration parameters + // self.Kademlia, + // stateStore, + // ) + // log.Debug(fmt.Sprintf("Set up swarm network with Kademlia hive")) + // + // setup cloud storage internal access layer + self.storage = storage.NewNetStore(hash, self.lstore, nil, config.StoreParams) + log.Debug("-> swarm net store shared access layer to Swarm Chunk Store") + + // set up DPA, the cloud storage local access layer + dpaChunkStore := storage.NewDpaChunkStore(self.lstore, self.storage) + log.Debug(fmt.Sprintf("-> Local Access to Swarm")) + + // Swarm Hash Merklised Chunking for Arbitrary-length Document/File storage + self.dpa = storage.NewDPA(dpaChunkStore, self.config.ChunkerParams) + log.Debug(fmt.Sprintf("-> Content Store API")) + + // netstore is broken, temp workaround to fiddle with pss + cachedir, err := ioutil.TempDir("", "bzz-tmp") + if err != nil { + return nil, err + } + self.dpa, err = storage.NewLocalDPA(cachedir) + if err != nil { + return nil, err + } + + // Pss = postal service over swarm (devp2p over bzz) + if pssEnabled { + pssparams := pss.NewPssParams(false) + self.pss = pss.NewPss(to, self.dpa, pssparams) + } + + // set up high level api + transactOpts := bind.NewKeyedTransactor(self.privateKey) + + if backend == (*ethclient.Client)(nil) { + log.Warn("No ENS, please specify non-empty --ethapi to use domain name resolution") + } else { + self.dns, err = ens.NewENS(transactOpts, config.EnsRoot, self.backend) + if err != nil { + return nil, err + } + } + log.Debug(fmt.Sprintf("-> Swarm Domain Name Registrar @ address %v", config.EnsRoot.Hex())) + + self.api = api.NewApi(self.dpa, self.dns) + + // Manifests for Smart Hosting + log.Debug(fmt.Sprintf("-> Web3 virtual server API")) + + self.sfs = fuse.NewSwarmFS(self.api) + log.Debug("-> Initializing Fuse file system") + + return self, nil +} + +/* +Start is called when the stack is started +* starts the network kademlia hive peer management +* (starts netStore level 0 api) +* starts DPA level 1 api (chunking -> store/retrieve requests) +* (starts level 2 api) +* starts http proxy server +* registers url scheme handlers for bzz, etc +* TODO: start subservices like sword, swear, swarmdns +*/ +// implements the node.Service interface +func (self *Swarm) Start(net *p2p.Server) error { + + // update uaddr to correct enode + newaddr := self.bzz.UpdateLocalAddr([]byte(net.Self().String())) + log.Warn("Updated bzz local addr", "oaddr", fmt.Sprintf("%s", newaddr.OAddr), "uaddr", fmt.Sprintf("%x", newaddr.UAddr)) + + // set chequebook + if self.swapEnabled { + ctx := context.Background() // The initial setup has no deadline. + err := self.SetChequebook(ctx) + if err != nil { + return fmt.Errorf("Unable to set chequebook for SWAP: %v", err) + } + log.Debug(fmt.Sprintf("-> cheque book for SWAP: %v", self.config.Swap.Chequebook())) + } else { + log.Debug(fmt.Sprintf("SWAP disabled: no cheque book set")) + } + + log.Warn(fmt.Sprintf("Starting Swarm service")) + + // self.hive.Start(net) + err := self.bzz.Start(net) + if err != nil { + log.Error("bzz failed", "err", err) + return err + } + log.Info(fmt.Sprintf("Swarm network started on bzz address: %x", self.bzz.Hive.Overlay.BaseAddr())) + + if self.pss != nil { + self.pss.Start(net) + log.Info("Pss started") + pss.RegisterPssProtocol(self.pss, &psschat.ChatTopic, psschat.ChatProtocol, psschat.New(nil, nil, func(ctrl *psschat.ChatCtrl) { + if ctrl.OutC != nil { + go func() { + for { + select { + case msg := <-ctrl.OutC: + err := ctrl.Peer.Send(msg) + if err != nil { + // do something with ctrl.ConnC here + //pp.Drop(err) + //return + } + } + } + }() + } + + })) + } + + self.dpa.Start() + log.Debug(fmt.Sprintf("Swarm DPA started")) + + // start swarm http proxy server + if self.config.Port != "" { + addr := ":" + self.config.Port + go httpapi.StartHttpServer(self.api, &httpapi.ServerConfig{ + Addr: addr, + CorsString: self.corsString, + }) + } + + log.Debug(fmt.Sprintf("Swarm http proxy started on port: %v", self.config.Port)) + + if self.corsString != "" { + log.Debug(fmt.Sprintf("Swarm http proxy started with corsdomain: %v", self.corsString)) + } + + return nil +} + +// implements the node.Service interface +// stops all component services. +func (self *Swarm) Stop() error { + self.dpa.Stop() + //self.hive.Stop() + self.bzz.Stop() + //if self.pss != nil { + // self.pss.Stop() + //} + if ch := self.config.Swap.Chequebook(); ch != nil { + ch.Stop() + ch.Save() + } + + if self.lstore != nil { + self.lstore.DbStore.Close() + } + self.sfs.Stop() + return self.config.Save() +} + +// implements the node.Service interface +func (self *Swarm) Protocols() (protos []p2p.Protocol) { + + for _, p := range self.bzz.Protocols() { + protos = append(protos, p) + } + + if self.pss != nil { + log.Warn("adding pss protos") + for _, p := range self.pss.Protocols() { + protos = append(protos, p) + } + } + // ct := network.BzzCodeMap() + // ct.Register(2, network.DiscoveryMsgs...) + + // proto := network.Bzz( + // self.hive.Overlay.GetAddr().Over(), + // self.hive.Overlay.GetAddr().Under(), + // ct, + // nil, + // nil, + // nil, + // ) + // + return +} + +// implements node.Service +// Apis returns the RPC Api descriptors the Swarm implementation offers +func (self *Swarm) APIs() []rpc.API { + + apis := []rpc.API{ + // public APIs + { + Namespace: "bzz", + Version: "0.1", + Service: &Info{self.config, chequebook.ContractParams}, + Public: true, + }, + // admin APIs + { + Namespace: "bzz", + Version: "0.1", + Service: api.NewControl(self.api, self.bzz.Hive), + Public: false, + }, + { + Namespace: "chequebook", + Version: chequebook.Version, + Service: chequebook.NewApi(self.config.Swap.Chequebook), + Public: false, + }, + { + Namespace: "swarmfs", + Version: fuse.Swarmfs_Version, + Service: self.sfs, + Public: false, + }, + // storage APIs + // DEPRECATED: Use the HTTP API instead + { + Namespace: "bzz", + Version: "0.1", + Service: api.NewStorage(self.api), + Public: true, + }, + { + Namespace: "bzz", + Version: "0.1", + Service: api.NewFileSystem(self.api), + Public: false, + }, + // {Namespace, Version, api.NewAdmin(self), false}, + } + + for _, api := range self.bzz.APIs() { + apis = append(apis, api) + } + + if self.pss != nil { + for _, api := range self.pss.APIs() { + apis = append(apis, api) + } + } + + return apis +} + +func (self *Swarm) Api() *api.Api { + return self.api +} + +// SetChequebook ensures that the local checquebook is set up on chain. +func (self *Swarm) SetChequebook(ctx context.Context) error { + err := self.config.Swap.SetChequebook(ctx, self.backend, self.config.Path) + if err != nil { + return err + } + log.Info(fmt.Sprintf("new chequebook set (%v): saving config file, resetting all connections in the hive", self.config.Swap.Contract.Hex())) + self.config.Save() + return nil +} + +// Local swarm without netStore +func NewLocalSwarm(datadir, port string) (self *Swarm, err error) { + + prvKey, err := crypto.GenerateKey() + if err != nil { + return + } + + config, err := api.NewConfig(datadir, common.Address{}, prvKey, network.NetworkId) + if err != nil { + return + } + config.Port = port + + dpa, err := storage.NewLocalDPA(datadir) + if err != nil { + return + } + + self = &Swarm{ + api: api.NewApi(dpa, nil), + config: config, + } + + return +} + +// serialisable info about swarm +type Info struct { + *api.Config + *chequebook.Params +} + +func (self *Info) Info() *Info { + return self +}