| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | // 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 <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package swarm | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2017-03-22 18:20:33 +01:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	"crypto/ecdsa" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2018-07-13 17:40:28 +02:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2017-12-01 10:32:14 +01:00
										 |  |  | 	"math/big" | 
					
						
							| 
									
										
										
										
											2017-05-21 23:56:40 -07:00
										 |  |  | 	"net" | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2017-12-13 10:23:11 +01:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2017-12-01 10:32:14 +01:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2017-12-13 10:23:11 +01:00
										 |  |  | 	"unicode" | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"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" | 
					
						
							| 
									
										
										
										
											2017-04-13 04:06:19 -05:00
										 |  |  | 	"github.com/ethereum/go-ethereum/ethclient" | 
					
						
							| 
									
										
										
										
											2018-02-23 14:19:59 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/metrics" | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/p2p" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/p2p/discover" | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/p2p/protocols" | 
					
						
							| 
									
										
										
										
											2017-12-01 10:32:14 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/params" | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/rpc" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/swarm/api" | 
					
						
							|  |  |  | 	httpapi "github.com/ethereum/go-ethereum/swarm/api/http" | 
					
						
							| 
									
										
										
										
											2017-04-12 05:36:02 +05:30
										 |  |  | 	"github.com/ethereum/go-ethereum/swarm/fuse" | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/swarm/log" | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/swarm/network" | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/swarm/network/stream" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/swarm/pss" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/swarm/state" | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/swarm/storage" | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/swarm/storage/mock" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/swarm/storage/mru" | 
					
						
							| 
									
										
										
										
											2018-07-13 17:40:28 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/swarm/tracing" | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-23 14:19:59 +01:00
										 |  |  | var ( | 
					
						
							|  |  |  | 	startTime          time.Time | 
					
						
							|  |  |  | 	updateGaugesPeriod = 5 * time.Second | 
					
						
							|  |  |  | 	startCounter       = metrics.NewRegisteredCounter("stack,start", nil) | 
					
						
							|  |  |  | 	stopCounter        = metrics.NewRegisteredCounter("stack,stop", nil) | 
					
						
							|  |  |  | 	uptimeGauge        = metrics.NewRegisteredGauge("stack.uptime", nil) | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	requestsCacheGauge = metrics.NewRegisteredGauge("storage.cache.requests.size", nil) | 
					
						
							| 
									
										
										
										
											2018-02-23 14:19:59 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | // the swarm stack | 
					
						
							|  |  |  | type Swarm struct { | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	config      *api.Config        // swarm configuration | 
					
						
							|  |  |  | 	api         *api.API           // high level api layer (fs/manifest) | 
					
						
							|  |  |  | 	dns         api.Resolver       // DNS registrar | 
					
						
							|  |  |  | 	fileStore   *storage.FileStore // distributed preimage archive, the local API to the storage with document level storage/retrieval support | 
					
						
							|  |  |  | 	streamer    *stream.Registry | 
					
						
							|  |  |  | 	bzz         *network.Bzz       // the logistic manager | 
					
						
							|  |  |  | 	backend     chequebook.Backend // simple blockchain Backend | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	privateKey  *ecdsa.PrivateKey | 
					
						
							| 
									
										
										
										
											2017-01-05 11:57:41 +01:00
										 |  |  | 	corsString  string | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	swapEnabled bool | 
					
						
							| 
									
										
										
										
											2018-09-13 11:42:19 +02:00
										 |  |  | 	netStore    *storage.NetStore | 
					
						
							|  |  |  | 	sfs         *fuse.SwarmFS // need this to cleanup all the active mounts on node exit | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	ps          *pss.Pss | 
					
						
							| 
									
										
										
										
											2018-07-13 17:40:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	tracerClose io.Closer | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type SwarmAPI struct { | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	Api     *api.API | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	Backend chequebook.Backend | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (self *Swarm) API() *SwarmAPI { | 
					
						
							|  |  |  | 	return &SwarmAPI{ | 
					
						
							|  |  |  | 		Api:     self.api, | 
					
						
							|  |  |  | 		Backend: self.backend, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // creates a new swarm service instance | 
					
						
							|  |  |  | // implements node.Service | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | // If mockStore is not nil, it will be used as the storage for chunk data. | 
					
						
							|  |  |  | // MockStore should be used only for testing. | 
					
						
							|  |  |  | func NewSwarm(config *api.Config, mockStore *mock.NodeStore) (self *Swarm, err error) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if bytes.Equal(common.FromHex(config.PublicKey), storage.ZeroAddr) { | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 		return nil, fmt.Errorf("empty public key") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	if bytes.Equal(common.FromHex(config.BzzKey), storage.ZeroAddr) { | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 		return nil, fmt.Errorf("empty bzz key") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	var backend chequebook.Backend | 
					
						
							|  |  |  | 	if config.SwapAPI != "" && config.SwapEnabled { | 
					
						
							|  |  |  | 		log.Info("connecting to SWAP API", "url", config.SwapAPI) | 
					
						
							|  |  |  | 		backend, err = ethclient.Dial(config.SwapAPI) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, fmt.Errorf("error connecting to SWAP API %s: %s", config.SwapAPI, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	self = &Swarm{ | 
					
						
							|  |  |  | 		config:     config, | 
					
						
							|  |  |  | 		backend:    backend, | 
					
						
							|  |  |  | 		privateKey: config.ShiftPrivateKey(), | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-21 10:34:10 +02:00
										 |  |  | 	log.Debug("Setting up Swarm service components") | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	config.HiveParams.Discovery = true | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	nodeID, err := discover.HexID(config.NodeID) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	addr := &network.BzzAddr{ | 
					
						
							|  |  |  | 		OAddr: common.FromHex(config.BzzKey), | 
					
						
							|  |  |  | 		UAddr: []byte(discover.NewNode(nodeID, net.IP{127, 0, 0, 1}, 30303, 30303).String()), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bzzconfig := &network.BzzConfig{ | 
					
						
							|  |  |  | 		NetworkID:    config.NetworkID, | 
					
						
							|  |  |  | 		OverlayAddr:  addr.OAddr, | 
					
						
							|  |  |  | 		UnderlayAddr: addr.UAddr, | 
					
						
							|  |  |  | 		HiveParams:   config.HiveParams, | 
					
						
							| 
									
										
										
										
											2018-08-07 15:34:11 +02:00
										 |  |  | 		LightNode:    config.LightNodeEnabled, | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	stateStore, err := state.NewDBStore(filepath.Join(config.Path, "state-store.db")) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	// set up high level api | 
					
						
							|  |  |  | 	var resolver *api.MultiResolver | 
					
						
							| 
									
										
										
										
											2017-12-18 16:22:39 +01:00
										 |  |  | 	if len(config.EnsAPIs) > 0 { | 
					
						
							|  |  |  | 		opts := []api.MultiResolverOption{} | 
					
						
							|  |  |  | 		for _, c := range config.EnsAPIs { | 
					
						
							|  |  |  | 			tld, endpoint, addr := parseEnsAPIAddress(c) | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 			r, err := newEnsClient(endpoint, addr, config, self.privateKey) | 
					
						
							| 
									
										
										
										
											2017-12-01 10:32:14 +01:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return nil, err | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-12-18 16:22:39 +01:00
										 |  |  | 			opts = append(opts, api.MultiResolverOptionWithResolver(r, tld)) | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-01 10:32:14 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 		resolver = api.NewMultiResolver(opts...) | 
					
						
							|  |  |  | 		self.dns = resolver | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-13 11:42:19 +02:00
										 |  |  | 	lstore, err := storage.NewLocalStore(config.LocalStoreParams, mockStore) | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2018-09-13 11:42:19 +02:00
										 |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	self.netStore, err = storage.NewNetStore(lstore, nil) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	to := network.NewKademlia( | 
					
						
							|  |  |  | 		common.FromHex(config.BzzKey), | 
					
						
							|  |  |  | 		network.NewKadParams(), | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2018-09-13 11:42:19 +02:00
										 |  |  | 	delivery := stream.NewDelivery(to, self.netStore) | 
					
						
							|  |  |  | 	self.netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, config.DeliverySkipCheck).New | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-13 11:42:19 +02:00
										 |  |  | 	self.streamer = stream.NewRegistry(addr, delivery, self.netStore, stateStore, &stream.RegistryOptions{ | 
					
						
							|  |  |  | 		SkipCheck:       config.SyncingSkipCheck, | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 		DoSync:          config.SyncEnabled, | 
					
						
							|  |  |  | 		DoRetrieve:      true, | 
					
						
							|  |  |  | 		SyncUpdateDelay: config.SyncUpdateDelay, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Swarm Hash Merklised Chunking for Arbitrary-length Document/File storage | 
					
						
							| 
									
										
										
										
											2018-09-13 11:42:19 +02:00
										 |  |  | 	self.fileStore = storage.NewFileStore(self.netStore, self.config.FileStoreParams) | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	var resourceHandler *mru.Handler | 
					
						
							| 
									
										
										
										
											2018-07-21 21:49:36 +02:00
										 |  |  | 	rhparams := &mru.HandlerParams{} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 16:03:56 +02:00
										 |  |  | 	resourceHandler = mru.NewHandler(rhparams) | 
					
						
							| 
									
										
										
										
											2018-09-13 11:42:19 +02:00
										 |  |  | 	resourceHandler.SetStore(self.netStore) | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-13 11:42:19 +02:00
										 |  |  | 	lstore.Validators = []storage.ChunkValidator{ | 
					
						
							| 
									
										
										
										
											2018-08-14 16:03:56 +02:00
										 |  |  | 		storage.NewContentAddressValidator(storage.MakeHashFunc(storage.DefaultHash)), | 
					
						
							|  |  |  | 		resourceHandler, | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-21 10:34:10 +02:00
										 |  |  | 	log.Debug("Setup local storage") | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	self.bzz = network.NewBzz(bzzconfig, to, stateStore, stream.Spec, self.streamer.Run) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Pss = postal service over swarm (devp2p over bzz) | 
					
						
							|  |  |  | 	self.ps, err = pss.NewPss(to, config.Pss) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if pss.IsActiveHandshake { | 
					
						
							|  |  |  | 		pss.SetHandshakeController(self.ps, pss.NewHandshakeParams()) | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-15 17:41:52 +02:00
										 |  |  | 	self.api = api.NewAPI(self.fileStore, self.dns, resourceHandler, self.privateKey) | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-12 05:36:02 +05:30
										 |  |  | 	self.sfs = fuse.NewSwarmFS(self.api) | 
					
						
							| 
									
										
										
										
											2018-08-21 10:34:10 +02:00
										 |  |  | 	log.Debug("Initialized FUSE filesystem") | 
					
						
							| 
									
										
										
										
											2017-03-23 19:26:06 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	return self, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-13 10:23:11 +01:00
										 |  |  | // parseEnsAPIAddress parses string according to format | 
					
						
							|  |  |  | // [tld:][contract-addr@]url and returns ENSClientConfig structure | 
					
						
							|  |  |  | // with endpoint, contract address and TLD. | 
					
						
							|  |  |  | func parseEnsAPIAddress(s string) (tld, endpoint string, addr common.Address) { | 
					
						
							|  |  |  | 	isAllLetterString := func(s string) bool { | 
					
						
							|  |  |  | 		for _, r := range s { | 
					
						
							|  |  |  | 			if !unicode.IsLetter(r) { | 
					
						
							|  |  |  | 				return false | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	endpoint = s | 
					
						
							|  |  |  | 	if i := strings.Index(endpoint, ":"); i > 0 { | 
					
						
							|  |  |  | 		if isAllLetterString(endpoint[:i]) && len(endpoint) > i+2 && endpoint[i+1:i+3] != "//" { | 
					
						
							|  |  |  | 			tld = endpoint[:i] | 
					
						
							|  |  |  | 			endpoint = endpoint[i+1:] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if i := strings.Index(endpoint, "@"); i > 0 { | 
					
						
							|  |  |  | 		addr = common.HexToAddress(endpoint[:i]) | 
					
						
							|  |  |  | 		endpoint = endpoint[i+1:] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return | 
					
						
							| 
									
										
										
										
											2017-12-01 10:32:14 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | // ensClient provides functionality for api.ResolveValidator | 
					
						
							|  |  |  | type ensClient struct { | 
					
						
							|  |  |  | 	*ens.ENS | 
					
						
							|  |  |  | 	*ethclient.Client | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-01 10:32:14 +01:00
										 |  |  | // newEnsClient creates a new ENS client for that is a consumer of | 
					
						
							|  |  |  | // a ENS API on a specific endpoint. It is used as a helper function | 
					
						
							|  |  |  | // for creating multiple resolvers in NewSwarm function. | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | func newEnsClient(endpoint string, addr common.Address, config *api.Config, privkey *ecdsa.PrivateKey) (*ensClient, error) { | 
					
						
							| 
									
										
										
										
											2017-12-01 10:32:14 +01:00
										 |  |  | 	log.Info("connecting to ENS API", "url", endpoint) | 
					
						
							|  |  |  | 	client, err := rpc.Dial(endpoint) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("error connecting to ENS API %s: %s", endpoint, err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	ethClient := ethclient.NewClient(client) | 
					
						
							| 
									
										
										
										
											2017-12-01 10:32:14 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ensRoot := config.EnsRoot | 
					
						
							| 
									
										
										
										
											2017-12-13 10:23:11 +01:00
										 |  |  | 	if addr != (common.Address{}) { | 
					
						
							|  |  |  | 		ensRoot = addr | 
					
						
							| 
									
										
										
										
											2017-12-01 10:32:14 +01:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		a, err := detectEnsAddr(client) | 
					
						
							|  |  |  | 		if err == nil { | 
					
						
							|  |  |  | 			ensRoot = a | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			log.Warn(fmt.Sprintf("could not determine ENS contract address, using default %s", ensRoot), "err", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	transactOpts := bind.NewKeyedTransactor(privkey) | 
					
						
							|  |  |  | 	dns, err := ens.NewENS(transactOpts, ensRoot, ethClient) | 
					
						
							| 
									
										
										
										
											2017-12-01 10:32:14 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	log.Debug(fmt.Sprintf("-> Swarm Domain Name Registrar %v @ address %v", endpoint, ensRoot.Hex())) | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	return &ensClient{ | 
					
						
							|  |  |  | 		ENS:    dns, | 
					
						
							|  |  |  | 		Client: ethClient, | 
					
						
							|  |  |  | 	}, err | 
					
						
							| 
									
										
										
										
											2017-12-01 10:32:14 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // detectEnsAddr determines the ENS contract address by getting both the | 
					
						
							|  |  |  | // version and genesis hash using the client and matching them to either | 
					
						
							|  |  |  | // mainnet or testnet addresses | 
					
						
							|  |  |  | func detectEnsAddr(client *rpc.Client) (common.Address, error) { | 
					
						
							|  |  |  | 	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) | 
					
						
							|  |  |  | 	defer cancel() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var version string | 
					
						
							|  |  |  | 	if err := client.CallContext(ctx, &version, "net_version"); err != nil { | 
					
						
							|  |  |  | 		return common.Address{}, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	block, err := ethclient.NewClient(client).BlockByNumber(ctx, big.NewInt(0)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return common.Address{}, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case version == "1" && block.Hash() == params.MainnetGenesisHash: | 
					
						
							|  |  |  | 		log.Info("using Mainnet ENS contract address", "addr", ens.MainNetAddress) | 
					
						
							|  |  |  | 		return ens.MainNetAddress, nil | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case version == "3" && block.Hash() == params.TestnetGenesisHash: | 
					
						
							|  |  |  | 		log.Info("using Testnet ENS contract address", "addr", ens.TestNetAddress) | 
					
						
							|  |  |  | 		return ens.TestNetAddress, nil | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return common.Address{}, fmt.Errorf("unknown version and genesis hash: %s %s", version, block.Hash()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | /* | 
					
						
							|  |  |  | 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 | 
					
						
							| 
									
										
										
										
											2017-05-21 23:56:40 -07:00
										 |  |  | func (self *Swarm) Start(srv *p2p.Server) error { | 
					
						
							| 
									
										
										
										
											2018-02-23 14:19:59 +01:00
										 |  |  | 	startTime = time.Now() | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-13 17:40:28 +02:00
										 |  |  | 	self.tracerClose = tracing.Closer | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	// update uaddr to correct enode | 
					
						
							|  |  |  | 	newaddr := self.bzz.UpdateLocalAddr([]byte(srv.Self().String())) | 
					
						
							| 
									
										
										
										
											2018-08-21 10:34:10 +02:00
										 |  |  | 	log.Info("Updated bzz local addr", "oaddr", fmt.Sprintf("%x", newaddr.OAddr), "uaddr", fmt.Sprintf("%s", newaddr.UAddr)) | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	// set chequebook | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	if self.config.SwapEnabled { | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 		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) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-02-22 14:10:07 +02:00
										 |  |  | 		log.Debug(fmt.Sprintf("-> cheque book for SWAP: %v", self.config.Swap.Chequebook())) | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2017-02-22 14:10:07 +02:00
										 |  |  | 		log.Debug(fmt.Sprintf("SWAP disabled: no cheque book set")) | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-21 10:34:10 +02:00
										 |  |  | 	log.Info("Starting bzz service") | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	err := self.bzz.Start(srv) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		log.Error("bzz failed", "err", err) | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-09-12 11:24:56 +02:00
										 |  |  | 	log.Info("Swarm network started", "bzzaddr", fmt.Sprintf("%x", self.bzz.Hive.BaseAddr())) | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if self.ps != nil { | 
					
						
							|  |  |  | 		self.ps.Start(srv) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// start swarm http proxy server | 
					
						
							|  |  |  | 	if self.config.Port != "" { | 
					
						
							| 
									
										
										
										
											2017-05-21 23:56:40 -07:00
										 |  |  | 		addr := net.JoinHostPort(self.config.ListenAddr, self.config.Port) | 
					
						
							| 
									
										
										
										
											2018-07-12 15:42:45 +02:00
										 |  |  | 		server := httpapi.NewServer(self.api, self.config.Cors) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-21 10:34:10 +02:00
										 |  |  | 		if self.config.Cors != "" { | 
					
						
							|  |  |  | 			log.Debug("Swarm HTTP proxy CORS headers", "allowedOrigins", self.config.Cors) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-21 10:34:10 +02:00
										 |  |  | 		log.Debug("Starting Swarm HTTP proxy", "port", self.config.Port) | 
					
						
							|  |  |  | 		go func() { | 
					
						
							|  |  |  | 			err := server.ListenAndServe(addr) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				log.Error("Could not start Swarm HTTP proxy", "err", err.Error()) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}() | 
					
						
							| 
									
										
										
										
											2017-01-05 11:57:41 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-23 14:19:59 +01:00
										 |  |  | 	self.periodicallyUpdateGauges() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	startCounter.Inc(1) | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	self.streamer.Start(srv) | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-23 14:19:59 +01:00
										 |  |  | func (self *Swarm) periodicallyUpdateGauges() { | 
					
						
							|  |  |  | 	ticker := time.NewTicker(updateGaugesPeriod) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	go func() { | 
					
						
							|  |  |  | 		for range ticker.C { | 
					
						
							|  |  |  | 			self.updateGauges() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (self *Swarm) updateGauges() { | 
					
						
							|  |  |  | 	uptimeGauge.Update(time.Since(startTime).Nanoseconds()) | 
					
						
							| 
									
										
										
										
											2018-09-13 11:42:19 +02:00
										 |  |  | 	requestsCacheGauge.Update(int64(self.netStore.RequestsCacheLen())) | 
					
						
							| 
									
										
										
										
											2018-02-23 14:19:59 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | // implements the node.Service interface | 
					
						
							|  |  |  | // stops all component services. | 
					
						
							|  |  |  | func (self *Swarm) Stop() error { | 
					
						
							| 
									
										
										
										
											2018-07-13 17:40:28 +02:00
										 |  |  | 	if self.tracerClose != nil { | 
					
						
							|  |  |  | 		err := self.tracerClose.Close() | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	if self.ps != nil { | 
					
						
							|  |  |  | 		self.ps.Stop() | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	if ch := self.config.Swap.Chequebook(); ch != nil { | 
					
						
							|  |  |  | 		ch.Stop() | 
					
						
							|  |  |  | 		ch.Save() | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-09 00:01:12 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-13 11:42:19 +02:00
										 |  |  | 	if self.netStore != nil { | 
					
						
							|  |  |  | 		self.netStore.Close() | 
					
						
							| 
									
										
										
										
											2017-02-09 00:01:12 +07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-03-23 19:26:06 +05:30
										 |  |  | 	self.sfs.Stop() | 
					
						
							| 
									
										
										
										
											2018-02-23 14:19:59 +01:00
										 |  |  | 	stopCounter.Inc(1) | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	self.streamer.Stop() | 
					
						
							|  |  |  | 	return self.bzz.Stop() | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // implements the node.Service interface | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | func (self *Swarm) Protocols() (protos []p2p.Protocol) { | 
					
						
							|  |  |  | 	protos = append(protos, self.bzz.Protocols()...) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if self.ps != nil { | 
					
						
							|  |  |  | 		protos = append(protos, self.ps.Protocols()...) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (self *Swarm) RegisterPssProtocol(spec *protocols.Spec, targetprotocol *p2p.Protocol, options *pss.ProtocolParams) (*pss.Protocol, error) { | 
					
						
							|  |  |  | 	if !pss.IsActiveProtocol { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("Pss protocols not available (built with !nopssprotocol tag)") | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 	topic := pss.ProtocolTopic(spec) | 
					
						
							|  |  |  | 	return pss.RegisterProtocol(self.ps, &topic, spec, targetprotocol, options) | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // implements node.Service | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | // APIs returns the RPC API descriptors the Swarm implementation offers | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | func (self *Swarm) APIs() []rpc.API { | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	apis := []rpc.API{ | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 		// public APIs | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			Namespace: "bzz", | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 			Version:   "3.0", | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 			Service:   &Info{self.config, chequebook.ContractParams}, | 
					
						
							|  |  |  | 			Public:    true, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		// admin APIs | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			Namespace: "bzz", | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 			Version:   "3.0", | 
					
						
							|  |  |  | 			Service:   api.NewControl(self.api, self.bzz.Hive), | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 			Public:    false, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			Namespace: "chequebook", | 
					
						
							|  |  |  | 			Version:   chequebook.Version, | 
					
						
							|  |  |  | 			Service:   chequebook.NewApi(self.config.Swap.Chequebook), | 
					
						
							|  |  |  | 			Public:    false, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2017-03-23 19:26:06 +05:30
										 |  |  | 		{ | 
					
						
							|  |  |  | 			Namespace: "swarmfs", | 
					
						
							| 
									
										
										
										
											2017-04-12 05:36:02 +05:30
										 |  |  | 			Version:   fuse.Swarmfs_Version, | 
					
						
							| 
									
										
										
										
											2017-03-23 19:26:06 +05:30
										 |  |  | 			Service:   self.sfs, | 
					
						
							|  |  |  | 			Public:    false, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	apis = append(apis, self.bzz.APIs()...) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if self.ps != nil { | 
					
						
							|  |  |  | 		apis = append(apis, self.ps.APIs()...) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return apis | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-20 14:06:27 +02:00
										 |  |  | func (self *Swarm) Api() *api.API { | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	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 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-22 14:10:07 +02:00
										 |  |  | 	log.Info(fmt.Sprintf("new chequebook set (%v): saving config file, resetting all connections in the hive", self.config.Swap.Contract.Hex())) | 
					
						
							| 
									
										
										
										
											2016-08-29 21:18:00 +02:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // serialisable info about swarm | 
					
						
							|  |  |  | type Info struct { | 
					
						
							|  |  |  | 	*api.Config | 
					
						
							|  |  |  | 	*chequebook.Params | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (self *Info) Info() *Info { | 
					
						
							|  |  |  | 	return self | 
					
						
							|  |  |  | } |