github.com/daeglee/go-ethereum@v0.0.0-20190504220456-cad3e8d18e9b/swarm/network/simulation/node.go (about) 1 // Copyright 2018 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 simulation 18 19 import ( 20 "bytes" 21 "context" 22 "crypto/ecdsa" 23 "encoding/json" 24 "errors" 25 "io/ioutil" 26 "math/rand" 27 "os" 28 "sync" 29 "time" 30 31 "github.com/ethereum/go-ethereum/crypto" 32 "github.com/ethereum/go-ethereum/p2p/enode" 33 "github.com/ethereum/go-ethereum/p2p/simulations" 34 "github.com/ethereum/go-ethereum/p2p/simulations/adapters" 35 "github.com/ethereum/go-ethereum/swarm/network" 36 ) 37 38 var ( 39 BucketKeyBzzPrivateKey BucketKey = "bzzprivkey" 40 ) 41 42 // NodeIDs returns NodeIDs for all nodes in the network. 43 func (s *Simulation) NodeIDs() (ids []enode.ID) { 44 nodes := s.Net.GetNodes() 45 ids = make([]enode.ID, len(nodes)) 46 for i, node := range nodes { 47 ids[i] = node.ID() 48 } 49 return ids 50 } 51 52 // UpNodeIDs returns NodeIDs for nodes that are up in the network. 53 func (s *Simulation) UpNodeIDs() (ids []enode.ID) { 54 nodes := s.Net.GetNodes() 55 for _, node := range nodes { 56 if node.Up() { 57 ids = append(ids, node.ID()) 58 } 59 } 60 return ids 61 } 62 63 // DownNodeIDs returns NodeIDs for nodes that are stopped in the network. 64 func (s *Simulation) DownNodeIDs() (ids []enode.ID) { 65 nodes := s.Net.GetNodes() 66 for _, node := range nodes { 67 if !node.Up() { 68 ids = append(ids, node.ID()) 69 } 70 } 71 return ids 72 } 73 74 // AddNodeOption defines the option that can be passed 75 // to Simulation.AddNode method. 76 type AddNodeOption func(*adapters.NodeConfig) 77 78 // AddNodeWithMsgEvents sets the EnableMsgEvents option 79 // to NodeConfig. 80 func AddNodeWithMsgEvents(enable bool) AddNodeOption { 81 return func(o *adapters.NodeConfig) { 82 o.EnableMsgEvents = enable 83 } 84 } 85 86 // AddNodeWithService specifies a service that should be 87 // started on a node. This option can be repeated as variadic 88 // argument toe AddNode and other add node related methods. 89 // If AddNodeWithService is not specified, all services will be started. 90 func AddNodeWithService(serviceName string) AddNodeOption { 91 return func(o *adapters.NodeConfig) { 92 o.Services = append(o.Services, serviceName) 93 } 94 } 95 96 // AddNode creates a new node with random configuration, 97 // applies provided options to the config and adds the node to network. 98 // By default all services will be started on a node. If one or more 99 // AddNodeWithService option are provided, only specified services will be started. 100 func (s *Simulation) AddNode(opts ...AddNodeOption) (id enode.ID, err error) { 101 conf := adapters.RandomNodeConfig() 102 for _, o := range opts { 103 o(conf) 104 } 105 if len(conf.Services) == 0 { 106 conf.Services = s.serviceNames 107 } 108 109 // add ENR records to the underlying node 110 // most importantly the bzz overlay address 111 // 112 // for now we have no way of setting bootnodes or lightnodes in sims 113 // so we just let them be set to false 114 // they should perhaps be possible to override them with AddNodeOption 115 bzzPrivateKey, err := BzzPrivateKeyFromConfig(conf) 116 if err != nil { 117 return enode.ID{}, err 118 } 119 120 enodeParams := &network.EnodeParams{ 121 PrivateKey: bzzPrivateKey, 122 } 123 record, err := network.NewEnodeRecord(enodeParams) 124 conf.Record = *record 125 126 // Add the bzz address to the node config 127 node, err := s.Net.NewNodeWithConfig(conf) 128 if err != nil { 129 return id, err 130 } 131 s.buckets[node.ID()] = new(sync.Map) 132 s.SetNodeItem(node.ID(), BucketKeyBzzPrivateKey, bzzPrivateKey) 133 134 return node.ID(), s.Net.Start(node.ID()) 135 } 136 137 // AddNodes creates new nodes with random configurations, 138 // applies provided options to the config and adds nodes to network. 139 func (s *Simulation) AddNodes(count int, opts ...AddNodeOption) (ids []enode.ID, err error) { 140 ids = make([]enode.ID, 0, count) 141 for i := 0; i < count; i++ { 142 id, err := s.AddNode(opts...) 143 if err != nil { 144 return nil, err 145 } 146 ids = append(ids, id) 147 } 148 return ids, nil 149 } 150 151 // AddNodesAndConnectFull is a helpper method that combines 152 // AddNodes and ConnectNodesFull. Only new nodes will be connected. 153 func (s *Simulation) AddNodesAndConnectFull(count int, opts ...AddNodeOption) (ids []enode.ID, err error) { 154 if count < 2 { 155 return nil, errors.New("count of nodes must be at least 2") 156 } 157 ids, err = s.AddNodes(count, opts...) 158 if err != nil { 159 return nil, err 160 } 161 err = s.Net.ConnectNodesFull(ids) 162 if err != nil { 163 return nil, err 164 } 165 return ids, nil 166 } 167 168 // AddNodesAndConnectChain is a helpper method that combines 169 // AddNodes and ConnectNodesChain. The chain will be continued from the last 170 // added node, if there is one in simulation using ConnectToLastNode method. 171 func (s *Simulation) AddNodesAndConnectChain(count int, opts ...AddNodeOption) (ids []enode.ID, err error) { 172 if count < 2 { 173 return nil, errors.New("count of nodes must be at least 2") 174 } 175 id, err := s.AddNode(opts...) 176 if err != nil { 177 return nil, err 178 } 179 err = s.Net.ConnectToLastNode(id) 180 if err != nil { 181 return nil, err 182 } 183 ids, err = s.AddNodes(count-1, opts...) 184 if err != nil { 185 return nil, err 186 } 187 ids = append([]enode.ID{id}, ids...) 188 err = s.Net.ConnectNodesChain(ids) 189 if err != nil { 190 return nil, err 191 } 192 return ids, nil 193 } 194 195 // AddNodesAndConnectRing is a helpper method that combines 196 // AddNodes and ConnectNodesRing. 197 func (s *Simulation) AddNodesAndConnectRing(count int, opts ...AddNodeOption) (ids []enode.ID, err error) { 198 if count < 2 { 199 return nil, errors.New("count of nodes must be at least 2") 200 } 201 ids, err = s.AddNodes(count, opts...) 202 if err != nil { 203 return nil, err 204 } 205 err = s.Net.ConnectNodesRing(ids) 206 if err != nil { 207 return nil, err 208 } 209 return ids, nil 210 } 211 212 // AddNodesAndConnectStar is a helpper method that combines 213 // AddNodes and ConnectNodesStar. 214 func (s *Simulation) AddNodesAndConnectStar(count int, opts ...AddNodeOption) (ids []enode.ID, err error) { 215 if count < 2 { 216 return nil, errors.New("count of nodes must be at least 2") 217 } 218 ids, err = s.AddNodes(count, opts...) 219 if err != nil { 220 return nil, err 221 } 222 err = s.Net.ConnectNodesStar(ids[1:], ids[0]) 223 if err != nil { 224 return nil, err 225 } 226 return ids, nil 227 } 228 229 // UploadSnapshot uploads a snapshot to the simulation 230 // This method tries to open the json file provided, applies the config to all nodes 231 // and then loads the snapshot into the Simulation network 232 func (s *Simulation) UploadSnapshot(ctx context.Context, snapshotFile string, opts ...AddNodeOption) error { 233 f, err := os.Open(snapshotFile) 234 if err != nil { 235 return err 236 } 237 defer f.Close() 238 239 jsonbyte, err := ioutil.ReadAll(f) 240 if err != nil { 241 return err 242 } 243 var snap simulations.Snapshot 244 if err := json.Unmarshal(jsonbyte, &snap); err != nil { 245 return err 246 } 247 248 //the snapshot probably has the property EnableMsgEvents not set 249 //set it to true (we need this to wait for messages before uploading) 250 for i := range snap.Nodes { 251 snap.Nodes[i].Node.Config.EnableMsgEvents = true 252 snap.Nodes[i].Node.Config.Services = s.serviceNames 253 for _, o := range opts { 254 o(snap.Nodes[i].Node.Config) 255 } 256 } 257 258 if err := s.Net.Load(&snap); err != nil { 259 return err 260 } 261 return s.WaitTillSnapshotRecreated(ctx, &snap) 262 } 263 264 // StartNode starts a node by NodeID. 265 func (s *Simulation) StartNode(id enode.ID) (err error) { 266 return s.Net.Start(id) 267 } 268 269 // StartRandomNode starts a random node. 270 func (s *Simulation) StartRandomNode() (id enode.ID, err error) { 271 n := s.Net.GetRandomDownNode() 272 if n == nil { 273 return id, ErrNodeNotFound 274 } 275 return n.ID(), s.Net.Start(n.ID()) 276 } 277 278 // StartRandomNodes starts random nodes. 279 func (s *Simulation) StartRandomNodes(count int) (ids []enode.ID, err error) { 280 ids = make([]enode.ID, 0, count) 281 for i := 0; i < count; i++ { 282 n := s.Net.GetRandomDownNode() 283 if n == nil { 284 return nil, ErrNodeNotFound 285 } 286 err = s.Net.Start(n.ID()) 287 if err != nil { 288 return nil, err 289 } 290 ids = append(ids, n.ID()) 291 } 292 return ids, nil 293 } 294 295 // StopNode stops a node by NodeID. 296 func (s *Simulation) StopNode(id enode.ID) (err error) { 297 return s.Net.Stop(id) 298 } 299 300 // StopRandomNode stops a random node. 301 func (s *Simulation) StopRandomNode() (id enode.ID, err error) { 302 n := s.Net.GetRandomUpNode() 303 if n == nil { 304 return id, ErrNodeNotFound 305 } 306 return n.ID(), s.Net.Stop(n.ID()) 307 } 308 309 // StopRandomNodes stops random nodes. 310 func (s *Simulation) StopRandomNodes(count int) (ids []enode.ID, err error) { 311 ids = make([]enode.ID, 0, count) 312 for i := 0; i < count; i++ { 313 n := s.Net.GetRandomUpNode() 314 if n == nil { 315 return nil, ErrNodeNotFound 316 } 317 err = s.Net.Stop(n.ID()) 318 if err != nil { 319 return nil, err 320 } 321 ids = append(ids, n.ID()) 322 } 323 return ids, nil 324 } 325 326 // seed the random generator for Simulation.randomNode. 327 func init() { 328 rand.Seed(time.Now().UnixNano()) 329 } 330 331 // derive a private key for swarm for the node key 332 // returns the private key used to generate the bzz key 333 func BzzPrivateKeyFromConfig(conf *adapters.NodeConfig) (*ecdsa.PrivateKey, error) { 334 // pad the seed key some arbitrary data as ecdsa.GenerateKey takes 40 bytes seed data 335 privKeyBuf := append(crypto.FromECDSA(conf.PrivateKey), []byte{0x62, 0x7a, 0x7a, 0x62, 0x7a, 0x7a, 0x62, 0x7a}...) 336 bzzPrivateKey, err := ecdsa.GenerateKey(crypto.S256(), bytes.NewReader(privKeyBuf)) 337 if err != nil { 338 return nil, err 339 } 340 return bzzPrivateKey, nil 341 }