go.dedis.ch/onet/v3@v3.2.11-0.20210930124529-e36530bca7ef/simulation.go (about) 1 package onet 2 3 import ( 4 "io/ioutil" 5 "net" 6 "os" 7 "strconv" 8 "strings" 9 "time" 10 11 "github.com/BurntSushi/toml" 12 "go.dedis.ch/kyber/v3" 13 "go.dedis.ch/kyber/v3/suites" 14 "go.dedis.ch/kyber/v3/util/key" 15 "go.dedis.ch/onet/v3/log" 16 "go.dedis.ch/onet/v3/network" 17 "golang.org/x/xerrors" 18 ) 19 20 type simulationCreate func(string) (Simulation, error) 21 22 var simulationRegistered map[string]simulationCreate 23 24 // SimulationFileName is the name of the (binary encoded) file containing the 25 // simulation config. 26 const SimulationFileName = "simulation.bin" 27 28 // Simulation is an interface needed by every protocol that wants to be available 29 // to be used in a simulation. 30 type Simulation interface { 31 // This has to initialise all necessary files and copy them to the 32 // 'dir'-directory. This directory will be accessible to all simulated 33 // hosts. 34 // Setup also gets a slice of all available hosts. In turn it has 35 // to return a tree using one or more of these hosts. It can create 36 // the Roster as desired, putting more than one ServerIdentity/Host on the same host. 37 // The 'config'-argument holds all arguments read from the runfile in 38 // toml-format. 39 Setup(dir string, hosts []string) (*SimulationConfig, error) 40 41 // Node will be run for every node and might be used to setup load- 42 // creation. It is started once the Host is set up and running, but before 43 // 'Run' 44 Node(config *SimulationConfig) error 45 46 // Run will begin with the simulation or return an error. It is sure 47 // to be run on the host where 'tree.Root' is. It should only return 48 // when all rounds are done. 49 Run(config *SimulationConfig) error 50 } 51 52 // SimulationConfig has to be returned from 'Setup' and will be passed to 53 // 'Run'. 54 type SimulationConfig struct { 55 // Represents the tree that has to be used 56 Tree *Tree 57 // The Roster used by the tree 58 Roster *Roster 59 // All private keys generated by 'Setup', indexed by the complete addresses 60 PrivateKeys map[network.Address]*SimulationPrivateKey 61 // If non-nil, points to our overlay 62 Overlay *Overlay 63 // If non-nil, points to our host 64 Server *Server 65 // Tells if the simulation should use TLS addresses; if not, use PlainTCP 66 TLS bool 67 // Additional configuration used to run 68 Config string 69 } 70 71 // SimulationPrivateKey contains the default private key and the service 72 // private keys for the ones registered with a suite. 73 type SimulationPrivateKey struct { 74 Private kyber.Scalar 75 Services []kyber.Scalar 76 } 77 78 // newSimulationPrivateKey instantiates and makes the map 79 func newSimulationPrivateKey(priv kyber.Scalar) *SimulationPrivateKey { 80 return &SimulationPrivateKey{ 81 Private: priv, 82 Services: make([]kyber.Scalar, 0), 83 } 84 } 85 86 // SimulationConfigFile stores the state of the simulation's config. 87 // Only used internally. 88 type SimulationConfigFile struct { 89 TreeMarshal *TreeMarshal 90 Roster *Roster 91 PrivateKeys map[network.Address]*SimulationPrivateKey 92 TLS bool 93 Config string 94 } 95 96 // LoadSimulationConfig gets all configuration from dir + SimulationFileName and instantiates the 97 // corresponding host 'ca'. 98 func LoadSimulationConfig(s, dir, ca string) ([]*SimulationConfig, error) { 99 // Have all servers created by NewServerTCP below put their 100 // db's into this simulation directory. 101 os.Setenv("CONODE_SERVICE_PATH", dir) 102 103 // TODO: Figure this out from the incoming simulation file somehow 104 suite := suites.MustFind(s) 105 106 network.RegisterMessage(SimulationConfigFile{}) 107 bin, err := ioutil.ReadFile(dir + "/" + SimulationFileName) 108 if err != nil { 109 return nil, xerrors.Errorf("reading file: %v", err) 110 } 111 _, msg, err := network.Unmarshal(bin, suite) 112 if err != nil { 113 return nil, xerrors.Errorf("unmarshaling: %v", err) 114 } 115 116 scf := msg.(*SimulationConfigFile) 117 sc := &SimulationConfig{ 118 Roster: scf.Roster, 119 PrivateKeys: scf.PrivateKeys, 120 TLS: scf.TLS, 121 Config: scf.Config, 122 } 123 sc.Tree, err = scf.TreeMarshal.MakeTree(sc.Roster) 124 if err != nil { 125 return nil, xerrors.Errorf("making tree: %v", err) 126 } 127 128 var ret []*SimulationConfig 129 if ca != "" { 130 if !strings.Contains(ca, ":") { 131 // to correctly match hosts a column is needed, else 132 // 10.255.0.1 would also match 10.255.0.10 and others 133 ca += ":" 134 } 135 for _, e := range sc.Roster.List { 136 if strings.Contains(e.Address.String(), ca) { 137 e.SetPrivate(scf.PrivateKeys[e.Address].Private) 138 // Populate the private key in the same array order 139 for i, privkey := range scf.PrivateKeys[e.Address].Services { 140 sid := e.ServiceIdentities[i] 141 suite, err := suites.Find(sid.Suite) 142 if err != nil { 143 return nil, xerrors.Errorf("Unknown suite with name %s", sid.Suite) 144 } 145 e.ServiceIdentities[i] = network.NewServiceIdentity(sid.Name, suite, sid.Public, privkey) 146 } 147 148 server := NewServerTCP(e, suite) 149 server.UnauthOk = true 150 server.Quiet = true 151 scNew := *sc 152 scNew.Server = server 153 scNew.Overlay = server.overlay 154 ret = append(ret, &scNew) 155 } 156 } 157 if len(ret) == 0 { 158 return nil, xerrors.New("Address not used in simulation: " + ca) 159 } 160 } else { 161 ret = append(ret, sc) 162 } 163 addr := string(sc.Roster.List[0].Address) 164 if strings.Contains(addr, "127.0.0.") { 165 // Now strip all superfluous numbers of localhost 166 for i := range sc.Roster.List { 167 _, port, _ := net.SplitHostPort(sc.Roster.List[i].Address.NetworkAddress()) 168 // put 127.0.0.1 because 127.0.0.X is not reachable on Mac OS X 169 if sc.TLS { 170 sc.Roster.List[i].Address = network.NewTLSAddress("127.0.0.1:" + port) 171 } else { 172 sc.Roster.List[i].Address = network.NewTCPAddress("127.0.0.1:" + port) 173 } 174 } 175 } 176 return ret, nil 177 } 178 179 // Save takes everything in the SimulationConfig structure and saves it to 180 // dir + SimulationFileName 181 func (sc *SimulationConfig) Save(dir string) error { 182 network.RegisterMessage(&SimulationConfigFile{}) 183 scf := &SimulationConfigFile{ 184 TreeMarshal: sc.Tree.MakeTreeMarshal(), 185 Roster: sc.Roster, 186 PrivateKeys: sc.PrivateKeys, 187 TLS: sc.TLS, 188 Config: sc.Config, 189 } 190 buf, err := network.Marshal(scf) 191 if err != nil { 192 log.Fatal(err) 193 } 194 err = ioutil.WriteFile(dir+"/"+SimulationFileName, buf, 0660) 195 if err != nil { 196 log.Fatal(err) 197 } 198 199 return nil 200 } 201 202 // GetService returns the service with the given name. 203 func (sc *SimulationConfig) GetService(name string) Service { 204 return sc.Server.serviceManager.service(name) 205 } 206 207 // SimulationRegister is must to be called to register a simulation. 208 // Protocol or simulation developers must not forget to call this function 209 // with the protocol's name. 210 func SimulationRegister(name string, sim simulationCreate) { 211 if simulationRegistered == nil { 212 simulationRegistered = make(map[string]simulationCreate) 213 } 214 simulationRegistered[name] = sim 215 } 216 217 // NewSimulation returns a simulation and decodes the 'conf' into the 218 // simulation-structure 219 func NewSimulation(name string, conf string) (Simulation, error) { 220 sim, ok := simulationRegistered[name] 221 if !ok { 222 return nil, xerrors.New("Didn't find simulation " + name) 223 } 224 simInst, err := sim(conf) 225 if err != nil { 226 return nil, xerrors.Errorf("creating simulation: %v", err) 227 } 228 _, err = toml.Decode(conf, simInst) 229 if err != nil { 230 return nil, xerrors.Errorf("decoding toml: %v", err) 231 } 232 return simInst, nil 233 } 234 235 // SimulationBFTree is the main struct storing the data for all the simulations 236 // which use a tree with a certain branching factor or depth. 237 type SimulationBFTree struct { 238 Rounds int 239 BF int 240 Hosts int 241 SingleHost bool 242 Depth int 243 Suite string 244 PreScript string // executable script to run before the simulation on each machine 245 TLS bool // tells if using TLS or PlainTCP addresses 246 } 247 248 // CreateRoster creates an Roster with the host-names in 'addresses'. 249 // It creates 's.Hosts' entries, starting from 'port' for each round through 250 // 'addresses'. The network.Address(es) created are of type TLS or PlainTCP, 251 // depending on the value 'TLS' in 'sc'. 252 func (s *SimulationBFTree) CreateRoster(sc *SimulationConfig, addresses []string, port int) { 253 start := time.Now() 254 sc.TLS = s.TLS 255 suite, err := suites.Find(s.Suite) 256 if err != nil { 257 log.Fatalf("Could not look up suite \"%v\": %+v", s.Suite, err) 258 } 259 nbrAddr := len(addresses) 260 if sc.PrivateKeys == nil { 261 sc.PrivateKeys = make(map[network.Address]*SimulationPrivateKey) 262 } 263 hosts := s.Hosts 264 if s.SingleHost { 265 // If we want to work with a single host, we only make one 266 // host per server 267 log.Fatal("Not supported yet") 268 hosts = nbrAddr 269 if hosts > s.Hosts { 270 hosts = s.Hosts 271 } 272 } 273 localhosts := false 274 listeners := make([]net.Listener, hosts) 275 services := make([]net.Listener, hosts) 276 if strings.Contains(addresses[0], "127.0.0.") { 277 localhosts = true 278 } 279 entities := make([]*network.ServerIdentity, hosts) 280 log.Lvl3("Doing", hosts, "hosts") 281 key := key.NewKeyPair(suite) 282 for c := 0; c < hosts; c++ { 283 key.Private.Add(key.Private, suite.Scalar().One()) 284 key.Public.Add(key.Public, suite.Point().Base()) 285 address := addresses[c%nbrAddr] + ":" 286 var add network.Address 287 if localhosts { 288 // If we have localhosts, we have to search for an empty port 289 port := 0 290 for port == 0 { 291 292 var err error 293 listeners[c], err = net.Listen("tcp", ":0") 294 if err != nil { 295 log.Fatal("Couldn't search for empty port:", err) 296 } 297 _, p, _ := net.SplitHostPort(listeners[c].Addr().String()) 298 port, _ = strconv.Atoi(p) 299 services[c], err = net.Listen("tcp", ":"+strconv.Itoa(port+1)) 300 if err != nil { 301 port = 0 302 } 303 } 304 address += strconv.Itoa(port) 305 if sc.TLS { 306 add = network.NewTLSAddress(address) 307 } else { 308 add = network.NewTCPAddress(address) 309 } 310 log.Lvl4("Found free port", address) 311 } else { 312 address += strconv.Itoa(port + (c/nbrAddr)*2) 313 if sc.TLS { 314 add = network.NewTLSAddress(address) 315 } else { 316 add = network.NewTCPAddress(address) 317 } 318 } 319 entities[c] = network.NewServerIdentity(key.Public.Clone(), add) 320 entities[c].SetPrivate(key.Private) 321 ServiceFactory.generateKeyPairs(entities[c]) 322 323 privConf := newSimulationPrivateKey(key.Private.Clone()) 324 sc.PrivateKeys[entities[c].Address] = privConf 325 for _, sid := range entities[c].ServiceIdentities { 326 privConf.Services = append(privConf.Services, sid.GetPrivate().Clone()) 327 } 328 } 329 330 // And close all our listeners 331 if localhosts { 332 for _, l := range listeners { 333 err := l.Close() 334 if err != nil { 335 log.Fatal("Couldn't close port:", l, err) 336 } 337 } 338 for _, l := range services { 339 err := l.Close() 340 if err != nil { 341 log.Fatal("Couldn't close port:", l, err) 342 } 343 } 344 } 345 346 sc.Roster = NewRoster(entities) 347 log.Lvl3("Creating entity List took: " + time.Now().Sub(start).String()) 348 } 349 350 // CreateTree the tree as defined in SimulationBFTree and stores the result 351 // in 'sc' 352 func (s *SimulationBFTree) CreateTree(sc *SimulationConfig) error { 353 log.Lvl3("CreateTree strarted") 354 start := time.Now() 355 if sc.Roster == nil { 356 return xerrors.New("Empty Roster") 357 } 358 sc.Tree = sc.Roster.GenerateBigNaryTree(s.BF, s.Hosts) 359 log.Lvl3("Creating tree took: " + time.Now().Sub(start).String()) 360 return nil 361 } 362 363 // Node - standard registers the entityList and the Tree with that Overlay, 364 // so we don't have to pass that around for the experiments. 365 func (s *SimulationBFTree) Node(sc *SimulationConfig) error { 366 sc.Overlay.RegisterTree(sc.Tree) 367 return nil 368 } 369 370 // GetSingleHost returns the 'SingleHost'-flag 371 func (sc SimulationConfig) GetSingleHost() bool { 372 var sh struct{ SingleHost bool } 373 _, err := toml.Decode(sc.Config, &sh) 374 if err != nil { 375 log.Error("Couldn't decode string", sc.Config, "into toml.") 376 return false 377 } 378 return sh.SingleHost 379 }