1 module tagion.testbench.services.trt_service; 2 // Default import list for bdd 3 import tagion.behaviour; 4 import tagion.hibon.Document; 5 import std.typecons : Tuple; 6 import tagion.testbench.tools.Environment; 7 import std.file; 8 import std.path : buildPath, setExtension; 9 import tagion.GlobalSignals; 10 import tagion.basic.Types : FileExtension; 11 import std.stdio; 12 import tagion.behaviour.Behaviour; 13 import tagion.services.options; 14 import tagion.testbench.services; 15 import tagion.tools.Basic; 16 import neuewelle = tagion.tools.neuewelle; 17 import tagion.utils.pretend_safe_concurrency; 18 import core.thread; 19 import core.time; 20 import tagion.logger.Logger; 21 import tagion.script.TagionCurrency; 22 import tagion.script.common; 23 import tagion.communication.HiRPC; 24 import tagion.testbench.services.sendcontract; 25 import tagion.wallet.SecureWallet; 26 import tagion.testbench.services.helper_functions; 27 import tagion.behaviour.BehaviourException : check; 28 import tagion.tools.wallet.WalletInterface; 29 30 enum CONTRACT_TIMEOUT = 40; 31 mixin Main!(_main); 32 33 void wrap_neuewelle(immutable(string)[] args) { 34 neuewelle._main(cast(string[]) args); 35 } 36 int _main(string[] args) { 37 auto module_path = env.bdd_log.buildPath(__MODULE__); 38 if (module_path.exists) { 39 rmdirRecurse(module_path); 40 } 41 mkdirRecurse(module_path); 42 string config_file = buildPath(module_path, "tagionwave.json"); 43 44 scope Options local_options = Options.defaultOptions; 45 local_options.dart.folder_path = buildPath(module_path); 46 local_options.trt.folder_path = buildPath(module_path); 47 local_options.trt.enable = true; 48 local_options.replicator.folder_path = buildPath(module_path, "recorders"); 49 local_options.epoch_creator.timeout = 500; 50 local_options.wave.prefix_format = "TRT_TEST_Node_%s_"; 51 local_options.subscription.address = contract_sock_addr("TRT_TEST_SUBSCRIPTION"); 52 local_options.save(config_file); 53 54 import std.algorithm; 55 import std.array; 56 import std.format; 57 import std.range; 58 import std.stdio; 59 import tagion.crypto.SecureInterfaceNet; 60 import tagion.crypto.SecureNet : StdSecureNet; 61 import tagion.dart.DART; 62 import tagion.dart.DARTFile; 63 import tagion.dart.Recorder; 64 StdSecureWallet[] wallets; 65 // create the wallets 66 foreach (i; 0 .. 5) { 67 StdSecureWallet secure_wallet; 68 secure_wallet = StdSecureWallet( 69 iota(0, 5).map!(n => format("%dquestion%d", i, n)).array, 70 iota(0, 5).map!(n => format("%danswer%d", i, n)).array, 71 4, 72 format("%04d", i), 73 ); 74 wallets ~= secure_wallet; 75 } 76 77 TagionBill requestAndForce(ref StdSecureWallet w, TagionCurrency amount) { 78 auto b = w.requestBill(amount); 79 w.addBill(b); 80 return b; 81 } 82 83 TagionBill[] bills; 84 foreach (ref wallet; wallets) { 85 foreach (i; 0 .. 3) { 86 bills ~= requestAndForce(wallet, 1000.TGN); 87 } 88 } 89 90 SecureNet net = new StdSecureNet(); 91 net.generateKeyPair("very_secret"); 92 93 auto factory = RecordFactory(net); 94 auto recorder = factory.recorder; 95 recorder.insert(bills, Archive.Type.ADD); 96 import tagion.trt.TRT; 97 auto trt_recorder = factory.recorder; 98 genesisTRT(bills, trt_recorder, net); 99 100 101 foreach (i; 0 .. local_options.wave.number_of_nodes) { 102 immutable prefix = format(local_options.wave.prefix_format, i); 103 const path = buildPath(local_options.dart.folder_path, prefix ~ local_options.dart.dart_filename); 104 const trt_path = buildPath(local_options.trt.folder_path, prefix ~ local_options.trt.trt_filename); 105 // writeln(path); 106 // writeln(trt_path); 107 DARTFile.create(path, net); 108 DARTFile.create(trt_path, net); 109 auto db = new DART(net, path); 110 auto trt_db = new DART(net, trt_path); 111 db.modify(recorder); 112 trt_db.modify(trt_recorder); 113 114 writefln("%s TRT bullseye: %(%02x%)", trt_path, trt_db.bullseye); 115 writefln("%s DART bullseye: %(%02x%)", path, db.bullseye); 116 117 db.close; 118 trt_db.close; 119 } 120 121 122 immutable neuewelle_args = ["trt_test", config_file, "--nodeopts", module_path]; // ~ args; 123 auto tid = spawn(&wrap_neuewelle, neuewelle_args); 124 import tagion.utils.JSONCommon : load; 125 126 Options[] node_opts; 127 128 Thread.sleep(15.seconds); 129 foreach (i; 0 .. local_options.wave.number_of_nodes) { 130 const filename = buildPath(module_path, format(local_options.wave.prefix_format ~ "opts", i).setExtension(FileExtension 131 .json)); 132 writeln(filename); 133 Options node_opt = load!(Options)(filename); 134 node_opts ~= node_opt; 135 } 136 auto name = "trt_testing"; 137 register(name, thisTid); 138 log.registerSubscriptionTask(name); 139 140 Thread.sleep(10.seconds); 141 142 143 auto feature = automation!(trt_service); 144 feature.SendAInoiceUsingTheTRT(node_opts[0], wallets[0], wallets[1]); 145 146 feature.run; 147 148 stopsignal.set; 149 Thread.sleep(6.seconds); 150 151 return 0; 152 153 } 154 155 156 157 158 enum feature = Feature( 159 "TRT Service test", 160 []); 161 162 alias FeatureContext = Tuple!( 163 SendAInoiceUsingTheTRT, "SendAInoiceUsingTheTRT", 164 FeatureGroup*, "result" 165 ); 166 167 @safe @Scenario("send a inoice using the TRT", 168 []) 169 class SendAInoiceUsingTheTRT { 170 Options opts1; 171 StdSecureWallet wallet1; 172 StdSecureWallet wallet2; 173 // 174 SignedContract signed_contract1; 175 SignedContract signed_contract2; 176 TagionCurrency amount; 177 TagionCurrency fee1; 178 TagionCurrency fee2; 179 180 HiRPC wallet1_hirpc; 181 HiRPC wallet2_hirpc; 182 TagionCurrency start_amount1; 183 TagionCurrency start_amount2; 184 this(Options opts1, ref StdSecureWallet wallet1, ref StdSecureWallet wallet2) { 185 this.wallet1 = wallet1; 186 this.wallet2 = wallet2; 187 this.opts1 = opts1; 188 189 wallet1_hirpc = HiRPC(wallet1.net); 190 wallet2_hirpc = HiRPC(wallet2.net); 191 start_amount1 = wallet1.calcTotal(wallet1.account.bills); 192 start_amount2 = wallet2.calcTotal(wallet2.account.bills); 193 194 } 195 196 @Given("i have a running network with a trt") 197 Document trt() { 198 writefln("address to dial %s", opts1.dart_interface.sock_addr); 199 auto wallet1_amount = getWalletInvoiceUpdateAmount(wallet1, opts1.dart_interface.sock_addr, wallet1_hirpc); 200 check(wallet1_amount == start_amount1, "balance should not have changed"); 201 auto wallet2_amount = getWalletInvoiceUpdateAmount(wallet2, opts1.dart_interface.sock_addr, wallet2_hirpc); 202 check(wallet2_amount == start_amount2, "balance should not have changed"); 203 // create a update request 204 return result_ok; 205 } 206 207 @When("i create and send a invoice") 208 Document invoice() { 209 amount = 100.TGN; 210 auto invoice_to_pay = wallet2.createInvoice("wowo", amount); 211 wallet2.registerInvoice(invoice_to_pay); 212 wallet1.payment([invoice_to_pay], signed_contract1, fee1); 213 (() @trusted => Thread.sleep(1.seconds))(); 214 wallet1.payment([invoice_to_pay], signed_contract2, fee2); 215 216 sendSubmitHiRPC(opts1.inputvalidator.sock_addr, wallet1_hirpc.submit(signed_contract1), wallet1.net); 217 sendSubmitHiRPC(opts1.inputvalidator.sock_addr, wallet1_hirpc.submit(signed_contract2), wallet1.net); 218 (() @trusted => Thread.sleep(CONTRACT_TIMEOUT.seconds))(); 219 return result_ok; 220 } 221 222 @When("i update my wallet using the pubkey lookup") 223 Document lookup() { 224 import std.format; 225 auto wallet1_amount = getWalletInvoiceUpdateAmount(wallet1, opts1.dart_interface.sock_addr, wallet1_hirpc); 226 auto wallet2_amount = getWalletInvoiceUpdateAmount(wallet2, opts1.dart_interface.sock_addr, wallet2_hirpc); 227 228 auto wallet1_expected = start_amount1 - fee1 - fee2 - 2*amount; 229 check(wallet1_amount == wallet1_expected, format("should have %s had %s", wallet1_expected, wallet1_amount)); 230 auto wallet2_expected = start_amount2 + 2*amount; 231 check(wallet2_amount == wallet2_expected, format("should have %s had %s", wallet2_expected, wallet2_amount)); 232 233 return result_ok; 234 } 235 236 @Then("the transaction should go through") 237 Document through() { 238 return Document(); 239 } 240 241 }