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 }