github.com/avence12/go-ethereum@v1.5.10-0.20170320123548-1dfd65f6d047/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/log"
    30  	"github.com/ethereum/go-ethereum/node"
    31  	"github.com/ethereum/go-ethereum/p2p"
    32  	"github.com/ethereum/go-ethereum/p2p/discover"
    33  	"github.com/ethereum/go-ethereum/rpc"
    34  	"github.com/ethereum/go-ethereum/swarm/api"
    35  	httpapi "github.com/ethereum/go-ethereum/swarm/api/http"
    36  	"github.com/ethereum/go-ethereum/swarm/network"
    37  	"github.com/ethereum/go-ethereum/swarm/storage"
    38  	"golang.org/x/net/context"
    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  }
    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  	log.Debug(fmt.Sprintf("Setting up Swarm service components"))
    91  
    92  	hash := storage.MakeHashFunc(config.ChunkerParams.Hash)
    93  	self.lstore, err = storage.NewLocalStore(hash, config.StoreParams)
    94  	if err != nil {
    95  		return
    96  	}
    97  
    98  	// setup local store
    99  	log.Debug(fmt.Sprintf("Set up local storage"))
   100  
   101  	self.dbAccess = network.NewDbAccess(self.lstore)
   102  	log.Debug(fmt.Sprintf("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  	log.Debug(fmt.Sprintf("Set up swarm network with Kademlia hive"))
   112  
   113  	// setup cloud storage backend
   114  	cloud := network.NewForwarder(self.hive)
   115  	log.Debug(fmt.Sprintf("-> set swarm forwarder as cloud storage backend"))
   116  	// setup cloud storage internal access layer
   117  
   118  	self.storage = storage.NewNetStore(hash, self.lstore, cloud, config.StoreParams)
   119  	log.Debug(fmt.Sprintf("-> 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, self.lstore, self.storage)
   123  	log.Debug(fmt.Sprintf("-> REmote Access to CHunks"))
   124  
   125  	// set up DPA, the cloud storage local access layer
   126  	dpaChunkStore := storage.NewDpaChunkStore(self.lstore, self.storage)
   127  	log.Debug(fmt.Sprintf("-> 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  	log.Debug(fmt.Sprintf("-> 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  	log.Debug(fmt.Sprintf("-> 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  	log.Debug(fmt.Sprintf("-> 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  		log.Debug(fmt.Sprintf("-> cheque book for SWAP: %v", self.config.Swap.Chequebook()))
   176  	} else {
   177  		log.Debug(fmt.Sprintf("SWAP disabled: no cheque book set"))
   178  	}
   179  
   180  	log.Warn(fmt.Sprintf("Starting Swarm service"))
   181  	self.hive.Start(
   182  		discover.PubkeyID(&net.PrivateKey.PublicKey),
   183  		func() string { return net.ListenAddr },
   184  		connectPeer,
   185  	)
   186  	log.Info(fmt.Sprintf("Swarm network started on bzz address: %v", self.hive.Addr()))
   187  
   188  	self.dpa.Start()
   189  	log.Debug(fmt.Sprintf("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  	log.Debug(fmt.Sprintf("Swarm http proxy started on port: %v", self.config.Port))
   198  
   199  	if self.corsString != "" {
   200  		log.Debug(fmt.Sprintf("Swarm http proxy started with corsdomain: %v", 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  
   216  	if self.lstore != nil {
   217  		self.lstore.DbStore.Close()
   218  	}
   219  
   220  	return self.config.Save()
   221  }
   222  
   223  // implements the node.Service interface
   224  func (self *Swarm) Protocols() []p2p.Protocol {
   225  	proto, err := network.Bzz(self.depo, self.backend, self.hive, self.dbAccess, self.config.Swap, self.config.SyncParams, self.config.NetworkId)
   226  	if err != nil {
   227  		return nil
   228  	}
   229  	return []p2p.Protocol{proto}
   230  }
   231  
   232  // implements node.Service
   233  // Apis returns the RPC Api descriptors the Swarm implementation offers
   234  func (self *Swarm) APIs() []rpc.API {
   235  	return []rpc.API{
   236  		// public APIs
   237  		{
   238  			Namespace: "bzz",
   239  			Version:   "0.1",
   240  			Service:   api.NewStorage(self.api),
   241  			Public:    true,
   242  		},
   243  		{
   244  			Namespace: "bzz",
   245  			Version:   "0.1",
   246  			Service:   &Info{self.config, chequebook.ContractParams},
   247  			Public:    true,
   248  		},
   249  		// admin APIs
   250  		{
   251  			Namespace: "bzz",
   252  			Version:   "0.1",
   253  			Service:   api.NewFileSystem(self.api),
   254  			Public:    false},
   255  		{
   256  			Namespace: "bzz",
   257  			Version:   "0.1",
   258  			Service:   api.NewControl(self.api, self.hive),
   259  			Public:    false,
   260  		},
   261  		{
   262  			Namespace: "chequebook",
   263  			Version:   chequebook.Version,
   264  			Service:   chequebook.NewApi(self.config.Swap.Chequebook),
   265  			Public:    false,
   266  		},
   267  		// {Namespace, Version, api.NewAdmin(self), false},
   268  	}
   269  }
   270  
   271  func (self *Swarm) Api() *api.Api {
   272  	return self.api
   273  }
   274  
   275  // SetChequebook ensures that the local checquebook is set up on chain.
   276  func (self *Swarm) SetChequebook(ctx context.Context) error {
   277  	err := self.config.Swap.SetChequebook(ctx, self.backend, self.config.Path)
   278  	if err != nil {
   279  		return err
   280  	}
   281  	log.Info(fmt.Sprintf("new chequebook set (%v): saving config file, resetting all connections in the hive", self.config.Swap.Contract.Hex()))
   282  	self.config.Save()
   283  	self.hive.DropAll()
   284  	return nil
   285  }
   286  
   287  // Local swarm without netStore
   288  func NewLocalSwarm(datadir, port string) (self *Swarm, err error) {
   289  
   290  	prvKey, err := crypto.GenerateKey()
   291  	if err != nil {
   292  		return
   293  	}
   294  
   295  	config, err := api.NewConfig(datadir, common.Address{}, prvKey, network.NetworkId)
   296  	if err != nil {
   297  		return
   298  	}
   299  	config.Port = port
   300  
   301  	dpa, err := storage.NewLocalDPA(datadir)
   302  	if err != nil {
   303  		return
   304  	}
   305  
   306  	self = &Swarm{
   307  		api:    api.NewApi(dpa, nil),
   308  		config: config,
   309  	}
   310  
   311  	return
   312  }
   313  
   314  // serialisable info about swarm
   315  type Info struct {
   316  	*api.Config
   317  	*chequebook.Params
   318  }
   319  
   320  func (self *Info) Info() *Info {
   321  	return self
   322  }