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