github.com/murrekatt/go-ethereum@v1.5.8-0.20170123175102-fc52f2c007fb/swarm/swarm.go (about)

     1  // Copyright 2016 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package swarm
    18  
    19  import (
    20  	"bytes"
    21  	"crypto/ecdsa"
    22  	"fmt"
    23  
    24  	"github.com/ethereum/go-ethereum/accounts/abi/bind"
    25  	"github.com/ethereum/go-ethereum/common"
    26  	"github.com/ethereum/go-ethereum/contracts/chequebook"
    27  	"github.com/ethereum/go-ethereum/contracts/ens"
    28  	"github.com/ethereum/go-ethereum/crypto"
    29  	"github.com/ethereum/go-ethereum/logger"
    30  	"github.com/ethereum/go-ethereum/logger/glog"
    31  	"github.com/ethereum/go-ethereum/node"
    32  	"github.com/ethereum/go-ethereum/p2p"
    33  	"github.com/ethereum/go-ethereum/p2p/discover"
    34  	"github.com/ethereum/go-ethereum/rpc"
    35  	"github.com/ethereum/go-ethereum/swarm/api"
    36  	httpapi "github.com/ethereum/go-ethereum/swarm/api/http"
    37  	"github.com/ethereum/go-ethereum/swarm/network"
    38  	"github.com/ethereum/go-ethereum/swarm/storage"
    39  	"golang.org/x/net/context"
    40  )
    41  
    42  // the swarm stack
    43  type Swarm struct {
    44  	config      *api.Config            // swarm configuration
    45  	api         *api.Api               // high level api layer (fs/manifest)
    46  	dns         api.Resolver           // DNS registrar
    47  	dbAccess    *network.DbAccess      // access to local chunk db iterator and storage counter
    48  	storage     storage.ChunkStore     // internal access to storage, common interface to cloud storage backends
    49  	dpa         *storage.DPA           // distributed preimage archive, the local API to the storage with document level storage/retrieval support
    50  	depo        network.StorageHandler // remote request handler, interface between bzz protocol and the storage
    51  	cloud       storage.CloudStore     // procurement, cloud storage backend (can multi-cloud)
    52  	hive        *network.Hive          // the logistic manager
    53  	backend     chequebook.Backend     // simple blockchain Backend
    54  	privateKey  *ecdsa.PrivateKey
    55  	corsString  string
    56  	swapEnabled bool
    57  }
    58  
    59  type SwarmAPI struct {
    60  	Api     *api.Api
    61  	Backend chequebook.Backend
    62  	PrvKey  *ecdsa.PrivateKey
    63  }
    64  
    65  func (self *Swarm) API() *SwarmAPI {
    66  	return &SwarmAPI{
    67  		Api:     self.api,
    68  		Backend: self.backend,
    69  		PrvKey:  self.privateKey,
    70  	}
    71  }
    72  
    73  // creates a new swarm service instance
    74  // implements node.Service
    75  func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, config *api.Config, swapEnabled, syncEnabled bool, cors string) (self *Swarm, err error) {
    76  	if bytes.Equal(common.FromHex(config.PublicKey), storage.ZeroKey) {
    77  		return nil, fmt.Errorf("empty public key")
    78  	}
    79  	if bytes.Equal(common.FromHex(config.BzzKey), storage.ZeroKey) {
    80  		return nil, fmt.Errorf("empty bzz key")
    81  	}
    82  
    83  	self = &Swarm{
    84  		config:      config,
    85  		swapEnabled: swapEnabled,
    86  		backend:     backend,
    87  		privateKey:  config.Swap.PrivateKey(),
    88  		corsString:  cors,
    89  	}
    90  	glog.V(logger.Debug).Infof("Setting up Swarm service components")
    91  
    92  	hash := storage.MakeHashFunc(config.ChunkerParams.Hash)
    93  	lstore, err := storage.NewLocalStore(hash, config.StoreParams)
    94  	if err != nil {
    95  		return
    96  	}
    97  
    98  	// setup local store
    99  	glog.V(logger.Debug).Infof("Set up local storage")
   100  
   101  	self.dbAccess = network.NewDbAccess(lstore)
   102  	glog.V(logger.Debug).Infof("Set up local db access (iterator/counter)")
   103  
   104  	// set up the kademlia hive
   105  	self.hive = network.NewHive(
   106  		common.HexToHash(self.config.BzzKey), // key to hive (kademlia base address)
   107  		config.HiveParams,                    // configuration parameters
   108  		swapEnabled,                          // SWAP enabled
   109  		syncEnabled,                          // syncronisation enabled
   110  	)
   111  	glog.V(logger.Debug).Infof("Set up swarm network with Kademlia hive")
   112  
   113  	// setup cloud storage backend
   114  	cloud := network.NewForwarder(self.hive)
   115  	glog.V(logger.Debug).Infof("-> set swarm forwarder as cloud storage backend")
   116  	// setup cloud storage internal access layer
   117  
   118  	self.storage = storage.NewNetStore(hash, lstore, cloud, config.StoreParams)
   119  	glog.V(logger.Debug).Infof("-> swarm net store shared access layer to Swarm Chunk Store")
   120  
   121  	// set up Depo (storage handler = cloud storage access layer for incoming remote requests)
   122  	self.depo = network.NewDepo(hash, lstore, self.storage)
   123  	glog.V(logger.Debug).Infof("-> REmote Access to CHunks")
   124  
   125  	// set up DPA, the cloud storage local access layer
   126  	dpaChunkStore := storage.NewDpaChunkStore(lstore, self.storage)
   127  	glog.V(logger.Debug).Infof("-> Local Access to Swarm")
   128  	// Swarm Hash Merklised Chunking for Arbitrary-length Document/File storage
   129  	self.dpa = storage.NewDPA(dpaChunkStore, self.config.ChunkerParams)
   130  	glog.V(logger.Debug).Infof("-> Content Store API")
   131  
   132  	// set up high level api
   133  	transactOpts := bind.NewKeyedTransactor(self.privateKey)
   134  
   135  	self.dns, err = ens.NewENS(transactOpts, config.EnsRoot, self.backend)
   136  	if err != nil {
   137  		return nil, err
   138  	}
   139  	glog.V(logger.Debug).Infof("-> Swarm Domain Name Registrar @ address %v", config.EnsRoot.Hex())
   140  
   141  	self.api = api.NewApi(self.dpa, self.dns)
   142  	// Manifests for Smart Hosting
   143  	glog.V(logger.Debug).Infof("-> Web3 virtual server API")
   144  
   145  	return self, nil
   146  }
   147  
   148  /*
   149  Start is called when the stack is started
   150  * starts the network kademlia hive peer management
   151  * (starts netStore level 0 api)
   152  * starts DPA level 1 api (chunking -> store/retrieve requests)
   153  * (starts level 2 api)
   154  * starts http proxy server
   155  * registers url scheme handlers for bzz, etc
   156  * TODO: start subservices like sword, swear, swarmdns
   157  */
   158  // implements the node.Service interface
   159  func (self *Swarm) Start(net *p2p.Server) error {
   160  	connectPeer := func(url string) error {
   161  		node, err := discover.ParseNode(url)
   162  		if err != nil {
   163  			return fmt.Errorf("invalid node URL: %v", err)
   164  		}
   165  		net.AddPeer(node)
   166  		return nil
   167  	}
   168  	// set chequebook
   169  	if self.swapEnabled {
   170  		ctx := context.Background() // The initial setup has no deadline.
   171  		err := self.SetChequebook(ctx)
   172  		if err != nil {
   173  			return fmt.Errorf("Unable to set chequebook for SWAP: %v", err)
   174  		}
   175  		glog.V(logger.Debug).Infof("-> cheque book for SWAP: %v", self.config.Swap.Chequebook())
   176  	} else {
   177  		glog.V(logger.Debug).Infof("SWAP disabled: no cheque book set")
   178  	}
   179  
   180  	glog.V(logger.Warn).Infof("Starting Swarm service")
   181  	self.hive.Start(
   182  		discover.PubkeyID(&net.PrivateKey.PublicKey),
   183  		func() string { return net.ListenAddr },
   184  		connectPeer,
   185  	)
   186  	glog.V(logger.Info).Infof("Swarm network started on bzz address: %v", self.hive.Addr())
   187  
   188  	self.dpa.Start()
   189  	glog.V(logger.Debug).Infof("Swarm DPA started")
   190  
   191  	// start swarm http proxy server
   192  	if self.config.Port != "" {
   193  		addr := ":" + self.config.Port
   194  		go httpapi.StartHttpServer(self.api, &httpapi.Server{Addr: addr, CorsString: self.corsString})
   195  	}
   196  
   197  	glog.V(logger.Debug).Infof("Swarm http proxy started on port: %v", self.config.Port)
   198  
   199  	if self.corsString != "" {
   200  		glog.V(logger.Debug).Infof("Swarm http proxy started with corsdomain:", self.corsString)
   201  	}
   202  
   203  	return nil
   204  }
   205  
   206  // implements the node.Service interface
   207  // stops all component services.
   208  func (self *Swarm) Stop() error {
   209  	self.dpa.Stop()
   210  	self.hive.Stop()
   211  	if ch := self.config.Swap.Chequebook(); ch != nil {
   212  		ch.Stop()
   213  		ch.Save()
   214  	}
   215  	return self.config.Save()
   216  }
   217  
   218  // implements the node.Service interface
   219  func (self *Swarm) Protocols() []p2p.Protocol {
   220  	proto, err := network.Bzz(self.depo, self.backend, self.hive, self.dbAccess, self.config.Swap, self.config.SyncParams, self.config.NetworkId)
   221  	if err != nil {
   222  		return nil
   223  	}
   224  	return []p2p.Protocol{proto}
   225  }
   226  
   227  // implements node.Service
   228  // Apis returns the RPC Api descriptors the Swarm implementation offers
   229  func (self *Swarm) APIs() []rpc.API {
   230  	return []rpc.API{
   231  		// public APIs
   232  		{
   233  			Namespace: "bzz",
   234  			Version:   "0.1",
   235  			Service:   api.NewStorage(self.api),
   236  			Public:    true,
   237  		},
   238  		{
   239  			Namespace: "bzz",
   240  			Version:   "0.1",
   241  			Service:   &Info{self.config, chequebook.ContractParams},
   242  			Public:    true,
   243  		},
   244  		// admin APIs
   245  		{
   246  			Namespace: "bzz",
   247  			Version:   "0.1",
   248  			Service:   api.NewFileSystem(self.api),
   249  			Public:    false},
   250  		{
   251  			Namespace: "bzz",
   252  			Version:   "0.1",
   253  			Service:   api.NewControl(self.api, self.hive),
   254  			Public:    false,
   255  		},
   256  		{
   257  			Namespace: "chequebook",
   258  			Version:   chequebook.Version,
   259  			Service:   chequebook.NewApi(self.config.Swap.Chequebook),
   260  			Public:    false,
   261  		},
   262  		// {Namespace, Version, api.NewAdmin(self), false},
   263  	}
   264  }
   265  
   266  func (self *Swarm) Api() *api.Api {
   267  	return self.api
   268  }
   269  
   270  // SetChequebook ensures that the local checquebook is set up on chain.
   271  func (self *Swarm) SetChequebook(ctx context.Context) error {
   272  	err := self.config.Swap.SetChequebook(ctx, self.backend, self.config.Path)
   273  	if err != nil {
   274  		return err
   275  	}
   276  	glog.V(logger.Info).Infof("new chequebook set (%v): saving config file, resetting all connections in the hive", self.config.Swap.Contract.Hex())
   277  	self.config.Save()
   278  	self.hive.DropAll()
   279  	return nil
   280  }
   281  
   282  // Local swarm without netStore
   283  func NewLocalSwarm(datadir, port string) (self *Swarm, err error) {
   284  
   285  	prvKey, err := crypto.GenerateKey()
   286  	if err != nil {
   287  		return
   288  	}
   289  
   290  	config, err := api.NewConfig(datadir, common.Address{}, prvKey, network.NetworkId)
   291  	if err != nil {
   292  		return
   293  	}
   294  	config.Port = port
   295  
   296  	dpa, err := storage.NewLocalDPA(datadir)
   297  	if err != nil {
   298  		return
   299  	}
   300  
   301  	self = &Swarm{
   302  		api:    api.NewApi(dpa, nil),
   303  		config: config,
   304  	}
   305  
   306  	return
   307  }
   308  
   309  // serialisable info about swarm
   310  type Info struct {
   311  	*api.Config
   312  	*chequebook.Params
   313  }
   314  
   315  func (self *Info) Info() *Info {
   316  	return self
   317  }