1 module tagion.testbench.services.sendcontract; 2 // Default import list for bdd 3 import core.thread; 4 import core.time; 5 import nngd; 6 import std.algorithm; 7 import std.array; 8 import std.format; 9 import std.stdio; 10 import std.typecons : Tuple; 11 import tagion.behaviour; 12 import tagion.communication.HiRPC; 13 import tagion.crypto.SecureInterfaceNet; 14 import tagion.crypto.SecureNet : StdSecureNet; 15 import tagion.dart.DARTBasic; 16 import tagion.dart.DARTcrud; 17 import tagion.hashgraph.Refinement; 18 import tagion.hibon.Document; 19 import tagion.hibon.Document; 20 import tagion.hibon.HiBONJSON; 21 import tagion.hibon.HiBONRecord; 22 import tagion.logger.LogRecords : LogInfo; 23 import tagion.logger.Logger; 24 import tagion.script.TagionCurrency; 25 import tagion.script.common; 26 import tagion.script.execute; 27 import tagion.services.options; 28 import tagion.testbench.services.helper_functions; 29 import tagion.testbench.tools.Environment; 30 import tagion.tools.wallet.WalletInterface; 31 import tagion.utils.pretend_safe_concurrency; 32 import tagion.wallet.SecureWallet : SecureWallet; 33 34 enum CONTRACT_TIMEOUT = 40; 35 36 alias StdSecureWallet = SecureWallet!StdSecureNet; 37 enum feature = Feature( 38 "send a contract to the network.", 39 []); 40 41 alias FeatureContext = Tuple!( 42 SendASingleTransactionFromAWalletToAnotherWallet, "SendASingleTransactionFromAWalletToAnotherWallet", 43 FeatureGroup*, "result" 44 ); 45 46 @safe @Scenario("send a single transaction from a wallet to another wallet.", 47 []) 48 class SendASingleTransactionFromAWalletToAnotherWallet { 49 50 Options opts; 51 StdSecureWallet[] wallets; 52 string dart_interface_sock_addr; 53 string inputvalidator_sock_addr; 54 TagionCurrency fee; 55 TagionCurrency amount; 56 TagionCurrency start_amount; 57 58 StdSecureWallet wallet1; 59 StdSecureWallet wallet2; 60 61 this(Options opts, StdSecureWallet[] wallets, string dart_interface_sock_addr, string inputvalidator_sock_addr, TagionCurrency start_amount) { 62 this.opts = opts; 63 this.wallets = wallets; 64 this.dart_interface_sock_addr = dart_interface_sock_addr; 65 this.start_amount = start_amount; 66 this.inputvalidator_sock_addr = inputvalidator_sock_addr; 67 68 } 69 70 bool epoch_on_startup; 71 72 @Given("i have a dart database with already existing bills linked to wallet1.") 73 Document _wallet1() @trusted { 74 // check that we are actually creating epochs; 75 submask.subscribe(StdRefinement.epoch_created); 76 writeln("waiting for epoch"); 77 auto received = receiveTimeout(30.seconds, (LogInfo _, const(Document) __) {}); 78 79 epoch_on_startup = received; 80 check(epoch_on_startup, "No epoch on startup"); 81 82 // create the hirpc request for checking if the bills are already in the system. 83 84 foreach (ref wallet; wallets) { 85 check(wallet.isLoggedin, "the wallet must be logged in!!!"); 86 const hirpc = HiRPC(wallet.net); 87 auto amount = getWalletUpdateAmount(wallet, dart_interface_sock_addr, hirpc); 88 check(wallet.calcTotal(wallet.account.bills) > 0.TGN, "did not receive money"); 89 check(wallet.calcTotal(wallet.account.bills) == start_amount, "money not correct"); 90 } 91 92 return result_ok; 93 } 94 95 @Given("i make a payment request from wallet2.") 96 Document _wallet2() @trusted { 97 check(epoch_on_startup, "No epoch on startup"); 98 wallet1 = wallets[1]; 99 wallet2 = wallets[2]; 100 amount = 1500.TGN; 101 auto payment_request = wallet2.requestBill(amount); 102 103 import tagion.hibon.HiBONtoText; 104 105 wallet1.account.bills 106 .each!(b => writefln("WALLET1 %s %s", wallet1.net.calcHash(b).encodeBase64, b.toPretty)); 107 SignedContract signed_contract; 108 check(wallet1.createPayment([payment_request], signed_contract, fee).value, "Error creating wallet payment"); 109 check(signed_contract !is SignedContract.init, "contract not updated"); 110 check(signed_contract.contract.inputs.uniq.array.length == signed_contract.contract.inputs.length, "signed contract inputs invalid"); 111 112 writefln("WALLET1 created contract: %s", signed_contract.toPretty); 113 114 auto wallet1_hirpc = HiRPC(wallet1.net); 115 auto hirpc_submit = wallet1_hirpc.submit(signed_contract); 116 117 auto result = sendSubmitHiRPC(inputvalidator_sock_addr, hirpc_submit, wallet1.net); 118 writefln("SUBMIT hirpc result: %s", result.toDoc.toPretty); 119 120 return result_ok; 121 } 122 123 @When("wallet1 pays contract to wallet2 and sends it to the network.") 124 Document network() @trusted { 125 check(epoch_on_startup, "No epoch on startup"); 126 writeln("WAITING FOR TIMEOUT"); 127 Thread.sleep(CONTRACT_TIMEOUT.seconds); 128 129 writeln("WALLET 1 request"); 130 131 const hirpc = HiRPC(wallet1.net); 132 auto wallet1_amount = getWalletUpdateAmount(wallet1, dart_interface_sock_addr, hirpc); 133 check(wallet1_amount < start_amount, format("no money withdrawn had %s", wallet1_amount)); 134 135 auto wallet1_expected = start_amount - amount - fee; 136 writefln("Wallet 1 total %s", wallet1_amount); 137 check(wallet1_amount == wallet1_expected, format("Wallet1 amount not correct had: %s expected: %s", wallet1_amount, wallet1_expected)); 138 return result_ok; 139 140 } 141 142 @Then("wallet2 should receive the payment.") 143 Document payment() @trusted { 144 check(epoch_on_startup, "No epoch on startup"); 145 const hirpc = HiRPC(wallet2.net); 146 auto wallet2_amount = getWalletUpdateAmount(wallet2, dart_interface_sock_addr, hirpc); 147 check(wallet2_amount > 0.TGN, "did not receive money"); 148 check(wallet2_amount == start_amount + amount, "did not receive correct amount of tagion"); 149 writefln("Wallet 2 total %s", wallet2.calcTotal(wallet2.account.bills)); 150 return result_ok; 151 } 152 153 }