1 module tagion.testbench.double_spend;
2 
3 import core.thread;
4 import core.time;
5 import std.file;
6 import std.path : buildPath, setExtension;
7 import std.stdio;
8 import tagion.GlobalSignals;
9 import tagion.actor;
10 import tagion.basic.Types : FileExtension;
11 import tagion.behaviour.Behaviour;
12 import tagion.logger.Logger;
13 import tagion.services.options;
14 import tagion.testbench.services;
15 import tagion.testbench.services.double_spend;
16 import tagion.testbench.tools.Environment;
17 import tagion.tools.Basic;
18 import neuewelle = tagion.tools.neuewelle;
19 import tagion.utils.pretend_safe_concurrency;
20 
21 mixin Main!(_main);
22 
23 void wrap_neuewelle(immutable(string)[] args) {
24     neuewelle._main(cast(string[]) args);
25 }
26 
27 int _main(string[] args) {
28     auto module_path = env.bdd_log.buildPath(__MODULE__);
29 
30     if (module_path.exists) {
31         rmdirRecurse(module_path);
32     }
33     mkdirRecurse(module_path);
34     string config_file = buildPath(module_path, "tagionwave.json");
35 
36     scope Options local_options = Options.defaultOptions;
37     local_options.dart.folder_path = buildPath(module_path);
38     local_options.replicator.folder_path = buildPath(module_path, "recorders");
39     local_options.wave.prefix_format = "DoubleSpend_Node_%s_";
40     local_options.subscription.address = contract_sock_addr("DOUBLE_SPEND_SUBSCRIPTION");
41 
42     local_options.save(config_file);
43 
44     import std.algorithm;
45     import std.array;
46     import std.format;
47     import std.range;
48     import std.stdio;
49     import tagion.crypto.SecureInterfaceNet;
50     import tagion.crypto.SecureNet : StdSecureNet;
51     import tagion.dart.DART;
52     import tagion.dart.DARTFile;
53     import tagion.dart.Recorder;
54     import tagion.script.TagionCurrency;
55     import tagion.script.common : TagionBill;
56     import tagion.testbench.services.sendcontract;
57     import tagion.wallet.SecureWallet;
58 
59     StdSecureWallet[] wallets;
60     // create the wallets
61     foreach (i; 0 .. 20) {
62         StdSecureWallet secure_wallet;
63         secure_wallet = StdSecureWallet(
64                 iota(0, 5).map!(n => format("%dquestion%d", i, n)).array,
65                 iota(0, 5).map!(n => format("%danswer%d", i, n)).array,
66                 4,
67                 format("%04d", i),
68         );
69         wallets ~= secure_wallet;
70     }
71 
72     // bills for the dart on startup
73 
74     TagionBill requestAndForce(ref StdSecureWallet w, TagionCurrency amount) {
75         auto b = w.requestBill(amount);
76         w.addBill(b);
77         return b;
78     }
79 
80     TagionBill[] bills;
81     foreach (ref wallet; wallets) {
82         foreach (i; 0 .. 3) {
83             bills ~= requestAndForce(wallet, 1000.TGN);
84         }
85     }
86 
87     SecureNet net = new StdSecureNet();
88     net.generateKeyPair("very_secret");
89 
90     auto factory = RecordFactory(net);
91     auto recorder = factory.recorder;
92     recorder.insert(bills, Archive.Type.ADD);
93 
94     foreach (i; 0 .. local_options.wave.number_of_nodes) {
95         immutable prefix = format(local_options.wave.prefix_format, i);
96         const path = buildPath(local_options.dart.folder_path, prefix ~ local_options.dart.dart_filename);
97         writeln(path);
98         DARTFile.create(path, net);
99         auto db = new DART(net, path);
100         db.modify(recorder);
101         db.close;
102     }
103 
104     immutable neuewelle_args = ["double_spend", config_file, "--nodeopts", module_path]; // ~ args;
105     auto tid = spawn(&wrap_neuewelle, neuewelle_args);
106 
107     import tagion.utils.JSONCommon : load;
108 
109     Options[] node_opts;
110 
111     Thread.sleep(5.seconds);
112     foreach (i; 0 .. local_options.wave.number_of_nodes) {
113 
114         const filename = buildPath(module_path, format(local_options.wave.prefix_format ~ "opts", i).setExtension(FileExtension
115                 .json));
116         writeln(filename);
117         Options node_opt = load!(Options)(filename);
118         node_opts ~= node_opt;
119     }
120 
121     writefln("INPUT SOCKET ADDRESS %s", node_opts[0].inputvalidator.sock_addr);
122 
123     Thread.sleep(15.seconds);
124     auto name = "double_spend_testing";
125     register(name, thisTid);
126     log.registerSubscriptionTask(name);
127     auto feature = automation!(double_spend);
128     feature.SameInputsSpendOnOneContract(node_opts[0], wallets[0], wallets[1]);
129     feature.OneContractWhereSomeBillsAreUsedTwice(node_opts[0], wallets[1], wallets[0]);
130     feature.DifferentContractsDifferentNodes(node_opts[0], node_opts[1], wallets[2], wallets[3]);
131     feature.SameContractDifferentNodes(node_opts[0], node_opts[1], wallets[4], wallets[5]);
132     feature.SameContractInDifferentEpochs(node_opts[0], wallets[6], wallets[7]);
133     feature.SameContractInDifferentEpochsDifferentNode(node_opts[2], node_opts[3], wallets[8], wallets[9]);
134     feature.TwoContractsSameOutput(node_opts[3], node_opts[4], wallets[10], wallets[11], wallets[12]);
135     feature.BillAge(node_opts[3], wallets[13], wallets[14]);
136     feature.run();
137 
138     stopsignal.set;
139     Thread.sleep(6.seconds);
140     return 0;
141 }