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