1 /** 
2  * Utilitty function for spawning neuewelle in mode0
3 **/
4 module tagion.wave.mode0;
5 
6 import std.array;
7 import std.file;
8 import std.algorithm;
9 import std.stdio;
10 import std.format;
11 import std.path;
12 import std.range;
13 
14 import tagion.crypto.SecureNet;
15 import tagion.crypto.Types;
16 import tagion.dart.DART;
17 import tagion.services.options;
18 import tagion.services.supervisor;
19 import tagion.utils.Term;
20 import tagion.tools.Basic;
21 import tagion.gossip.AddressBook;
22 import std.range : zip;
23 import tagion.hibon.HiBONRecord;
24 import tagion.hibon.Document;
25 import tagion.script.common : Epoch, GenesisEpoch;
26 import tagion.actor;
27 
28 // Checks if all nodes bullseyes are the same
29 bool isMode0BullseyeSame(const(Options[]) node_options, SecureNet __net) {
30     import std.typecons;
31     // extra check for mode0
32     // Check bullseyes
33     Fingerprint[] bullseyes;
34     foreach (node_opt; node_options) {
35         if (!node_opt.dart.dart_path.exists) {
36             stderr.writefln("Missing dartfile %s", node_opt.dart.dart_path);
37             return false;
38         }
39         Exception dart_exception;
40         DART db = new DART(__net, node_opt.dart.dart_path, dart_exception, Yes.read_only);
41         if (dart_exception !is null) {
42             throw dart_exception;
43         }
44         scope (exit) {
45             db.close();
46         }
47         auto b = Fingerprint(db.bullseye);
48         bullseyes ~= b;
49 
50     }
51     // check that all bullseyes are the same before boot
52     return bullseyes.all!(b => b == bullseyes[0]);
53 }
54 
55 const(Options)[] getMode0Options(const(Options) options, bool monitor = false) {
56     const number_of_nodes = options.wave.number_of_nodes;
57     const prefix_f = options.wave.prefix_format;
58     Options[] all_opts;
59     foreach (node_n; 0 .. number_of_nodes) {
60         auto opt = Options(options);
61         opt.setPrefix(format(prefix_f, node_n));
62         all_opts ~= opt;
63     }
64 
65     if (monitor) {
66         all_opts[0].monitor.enable = true;
67     }
68 
69     return all_opts;
70 }
71 
72 struct Node {
73     immutable(Options) opts;
74     shared(StdSecureNet) net;
75     Pubkey pkey;
76 }
77 
78 void spawnMode0(
79         const(Options)[] node_options,
80         ref ActorHandle[] supervisor_handles,
81         Node[] nodes,
82         Document epoch_head = Document.init) {
83 
84     if (epoch_head is Document.init) {
85         foreach (n; zip(nodes, node_options)) {
86             addressbook[n[0].pkey] = NodeAddress(n[1].task_names.epoch_creator);
87         }
88     }
89     else {
90         Pubkey[] keys;
91         if (epoch_head.isRecord!Epoch) {
92             assert(0, "not supported to boot from epoch yet");
93             keys = Epoch(epoch_head).active;
94         }
95         else {
96             auto genesis = GenesisEpoch(epoch_head);
97 
98             keys = genesis.nodes;
99             check(equal(keys, keys.uniq), "Duplicate node public keys in the genesis epoch");
100             check(keys.length == node_options.length, "There was not the same amount of configured nodes as in the genesis epoch");
101         }
102 
103         foreach (node_info; zip(keys, node_options)) {
104             verbose("adding addressbook ", node_info[0]);
105             addressbook[node_info[0]] = NodeAddress(node_info[1].task_names.epoch_creator);
106         }
107     }
108 
109     /// spawn the nodes
110     foreach (n; nodes) {
111         verbose("spawning supervisor ", n.opts.task_names.supervisor);
112         supervisor_handles ~= spawn!Supervisor(n.opts.task_names.supervisor, n.opts, n.net);
113     }
114 }