github.com/digdeepmining/go-atheios@v1.5.13-0.20180902133602-d5687a2e6f43/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/atheioschain/go-atheios/accounts/abi/bind"
    25  	"github.com/atheioschain/go-atheios/common"
    26  	"github.com/atheioschain/go-atheios/contracts/chequebook"
    27  	"github.com/atheioschain/go-atheios/contracts/ens"
    28  	"github.com/atheioschain/go-atheios/crypto"
    29  	"github.com/atheioschain/go-atheios/logger"
    30  	"github.com/atheioschain/go-atheios/logger/glog"
    31  	"github.com/atheioschain/go-atheios/node"
    32  	"github.com/atheioschain/go-atheios/p2p"
    33  	"github.com/atheioschain/go-atheios/p2p/discover"
    34  	"github.com/atheioschain/go-atheios/rpc"
    35  	"github.com/atheioschain/go-atheios/swarm/api"
    36  	httpapi "github.com/atheioschain/go-atheios/swarm/api/http"
    37  	"github.com/atheioschain/go-atheios/swarm/network"
    38  	"github.com/atheioschain/go-atheios/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  	lstore      *storage.LocalStore // local store, needs to store for releasing resources after node stopped
    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  	glog.V(logger.Debug).Infof("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  	glog.V(logger.Debug).Infof("Set up local storage")
   101  
   102  	self.dbAccess = network.NewDbAccess(self.lstore)
   103  	glog.V(logger.Debug).Infof("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  	glog.V(logger.Debug).Infof("Set up swarm network with Kademlia hive")
   113  
   114  	// setup cloud storage backend
   115  	cloud := network.NewForwarder(self.hive)
   116  	glog.V(logger.Debug).Infof("-> 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  	glog.V(logger.Debug).Infof("-> 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  	glog.V(logger.Debug).Infof("-> REmote Access to CHunks")
   125  
   126  	// set up DPA, the cloud storage local access layer
   127  	dpaChunkStore := storage.NewDpaChunkStore(self.lstore, self.storage)
   128  	glog.V(logger.Debug).Infof("-> 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  	glog.V(logger.Debug).Infof("-> 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  	glog.V(logger.Debug).Infof("-> 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  	glog.V(logger.Debug).Infof("-> Web3 virtual server API")
   145  
   146  	return self, nil
   147  }
   148  
   149  /*
   150  Start is called when the stack is started
   151  * starts the network kademlia hive peer management
   152  * (starts netStore level 0 api)
   153  * starts DPA level 1 api (chunking -> store/retrieve requests)
   154  * (starts level 2 api)
   155  * starts http proxy server
   156  * registers url scheme handlers for bzz, etc
   157  * TODO: start subservices like sword, swear, swarmdns
   158  */
   159  // implements the node.Service interface
   160  func (self *Swarm) Start(net *p2p.Server) error {
   161  	connectPeer := func(url string) error {
   162  		node, err := discover.ParseNode(url)
   163  		if err != nil {
   164  			return fmt.Errorf("invalid node URL: %v", err)
   165  		}
   166  		net.AddPeer(node)
   167  		return nil
   168  	}
   169  	// set chequebook
   170  	if self.swapEnabled {
   171  		ctx := context.Background() // The initial setup has no deadline.
   172  		err := self.SetChequebook(ctx)
   173  		if err != nil {
   174  			return fmt.Errorf("Unable to set chequebook for SWAP: %v", err)
   175  		}
   176  		glog.V(logger.Debug).Infof("-> cheque book for SWAP: %v", self.config.Swap.Chequebook())
   177  	} else {
   178  		glog.V(logger.Debug).Infof("SWAP disabled: no cheque book set")
   179  	}
   180  
   181  	glog.V(logger.Warn).Infof("Starting Swarm service")
   182  	self.hive.Start(
   183  		discover.PubkeyID(&net.PrivateKey.PublicKey),
   184  		func() string { return net.ListenAddr },
   185  		connectPeer,
   186  	)
   187  	glog.V(logger.Info).Infof("Swarm network started on bzz address: %v", self.hive.Addr())
   188  
   189  	self.dpa.Start()
   190  	glog.V(logger.Debug).Infof("Swarm DPA started")
   191  
   192  	// start swarm http proxy server
   193  	if self.config.Port != "" {
   194  		addr := ":" + self.config.Port
   195  		go httpapi.StartHttpServer(self.api, &httpapi.Server{Addr: addr, CorsString: self.corsString})
   196  	}
   197  
   198  	glog.V(logger.Debug).Infof("Swarm http proxy started on port: %v", self.config.Port)
   199  
   200  	if self.corsString != "" {
   201  		glog.V(logger.Debug).Infof("Swarm http proxy started with corsdomain:", self.corsString)
   202  	}
   203  
   204  	return nil
   205  }
   206  
   207  // implements the node.Service interface
   208  // stops all component services.
   209  func (self *Swarm) Stop() error {
   210  	self.dpa.Stop()
   211  	self.hive.Stop()
   212  	if ch := self.config.Swap.Chequebook(); ch != nil {
   213  		ch.Stop()
   214  		ch.Save()
   215  	}
   216  
   217  	if self.lstore != nil {
   218  		self.lstore.DbStore.Close()
   219  	}
   220  
   221  	return self.config.Save()
   222  }
   223  
   224  // implements the node.Service interface
   225  func (self *Swarm) Protocols() []p2p.Protocol {
   226  	proto, err := network.Bzz(self.depo, self.backend, self.hive, self.dbAccess, self.config.Swap, self.config.SyncParams, self.config.NetworkId)
   227  	if err != nil {
   228  		return nil
   229  	}
   230  	return []p2p.Protocol{proto}
   231  }
   232  
   233  // implements node.Service
   234  // Apis returns the RPC Api descriptors the Swarm implementation offers
   235  func (self *Swarm) APIs() []rpc.API {
   236  	return []rpc.API{
   237  		// public APIs
   238  		{
   239  			Namespace: "bzz",
   240  			Version:   "0.1",
   241  			Service:   api.NewStorage(self.api),
   242  			Public:    true,
   243  		},
   244  		{
   245  			Namespace: "bzz",
   246  			Version:   "0.1",
   247  			Service:   &Info{self.config, chequebook.ContractParams},
   248  			Public:    true,
   249  		},
   250  		// admin APIs
   251  		{
   252  			Namespace: "bzz",
   253  			Version:   "0.1",
   254  			Service:   api.NewFileSystem(self.api),
   255  			Public:    false},
   256  		{
   257  			Namespace: "bzz",
   258  			Version:   "0.1",
   259  			Service:   api.NewControl(self.api, self.hive),
   260  			Public:    false,
   261  		},
   262  		{
   263  			Namespace: "chequebook",
   264  			Version:   chequebook.Version,
   265  			Service:   chequebook.NewApi(self.config.Swap.Chequebook),
   266  			Public:    false,
   267  		},
   268  		// {Namespace, Version, api.NewAdmin(self), false},
   269  	}
   270  }
   271  
   272  func (self *Swarm) Api() *api.Api {
   273  	return self.api
   274  }
   275  
   276  // SetChequebook ensures that the local checquebook is set up on chain.
   277  func (self *Swarm) SetChequebook(ctx context.Context) error {
   278  	err := self.config.Swap.SetChequebook(ctx, self.backend, self.config.Path)
   279  	if err != nil {
   280  		return err
   281  	}
   282  	glog.V(logger.Info).Infof("new chequebook set (%v): saving config file, resetting all connections in the hive", self.config.Swap.Contract.Hex())
   283  	self.config.Save()
   284  	self.hive.DropAll()
   285  	return nil
   286  }
   287  
   288  // Local swarm without netStore
   289  func NewLocalSwarm(datadir, port string) (self *Swarm, err error) {
   290  
   291  	prvKey, err := crypto.GenerateKey()
   292  	if err != nil {
   293  		return
   294  	}
   295  
   296  	config, err := api.NewConfig(datadir, common.Address{}, prvKey, network.NetworkId)
   297  	if err != nil {
   298  		return
   299  	}
   300  	config.Port = port
   301  
   302  	dpa, err := storage.NewLocalDPA(datadir)
   303  	if err != nil {
   304  		return
   305  	}
   306  
   307  	self = &Swarm{
   308  		api:    api.NewApi(dpa, nil),
   309  		config: config,
   310  	}
   311  
   312  	return
   313  }
   314  
   315  // serialisable info about swarm
   316  type Info struct {
   317  	*api.Config
   318  	*chequebook.Params
   319  }
   320  
   321  func (self *Info) Info() *Info {
   322  	return self
   323  }