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 }