@@ -344,10 +344,159 @@ Extended::getLatestInclusion(const std::vector<Type::Trytes>& hashes) const {
344
344
return getInclusionStates (hashes, { getNodeInfo ().getLatestSolidSubtangleMilestone () });
345
345
}
346
346
347
+ // TODO Response ?
347
348
std::vector<Type::Trytes>
348
- Extended::prepareTransfers (const Type::Trytes&, int , const std::vector<Transfer>&,
349
- const std::string&, const std::vector<input>&) const {
350
- return {};
349
+ Extended::prepareTransfers (const Type::Trytes& seed, int security, std::vector<Transfer>& transfers,
350
+ const std::string& remainder, const std::vector<input>& inputs,
351
+ bool validateInputs) const {
352
+ Utils::StopWatch sw;
353
+ // Validate transfers object
354
+ if (!this ->isTransfersCollectionValid (transfers)) {
355
+ throw Errors::IllegalState (" Invalid transfer" );
356
+ }
357
+
358
+ // Validate the seed
359
+ if ((!Type::Seed::isValidSeed (seed))) {
360
+ throw Errors::IllegalState (" Invalid Seed" );
361
+ }
362
+
363
+ // Validate the security level
364
+ if (security < 1 || security > 3 ) {
365
+ throw Errors::IllegalState (" Invalid Security Level" );
366
+ }
367
+
368
+ Bundle bundle;
369
+ std::vector<std::string> signatureFragments;
370
+ long totalValue = 0 ;
371
+ std::string tag;
372
+ Crypto::Checksum cs;
373
+
374
+ // Iterate over all transfers, get totalValue
375
+ // and prepare the signatureFragments, message and tag
376
+ for (auto & transfer : transfers) {
377
+ // If address with checksum then remove checksum
378
+ if (cs.isValid (transfer.getAddress ()))
379
+ transfer.setAddress (cs.remove (transfer.getAddress ()));
380
+
381
+ int signatureMessageLength = 1 ;
382
+
383
+ // If message longer than 2187 trytes, increase signatureMessageLength (add 2nd transaction)
384
+ if (transfer.getMessage ().size () > MaxTrxMsgLength) {
385
+ // Get total length, message / maxLength (2187 trytes)
386
+ signatureMessageLength += std::floor (transfer.getMessage ().length () / MaxTrxMsgLength);
387
+
388
+ std::string msgCopy = transfer.getMessage ();
389
+
390
+ // While there is still a message, copy it
391
+ while (!msgCopy.empty ()) {
392
+ auto fragment = msgCopy.substr (0 , MaxTrxMsgLength);
393
+ msgCopy = msgCopy.substr (MaxTrxMsgLength);
394
+
395
+ // Pad remainder of fragment
396
+ fragment = Type::Utils::rightPad (transfer.getMessage (), MaxTrxMsgLength, ' 9' );
397
+
398
+ signatureFragments.push_back (fragment);
399
+ }
400
+ } else {
401
+ // Else, get single fragment with 2187 of 9's trytes
402
+ auto fragment = transfer.getMessage ().substr (0 , MaxTrxMsgLength);
403
+
404
+ fragment = Type::Utils::rightPad (fragment, MaxTrxMsgLength, ' 9' );
405
+
406
+ signatureFragments.push_back (fragment);
407
+ }
408
+
409
+ // get current timestamp in seconds
410
+ long timestamp = sw.now ().count ();
411
+
412
+ // If no tag defined, get 27 tryte tag.
413
+ tag = transfer.getTag ().empty () ? " 999999999999999999999999999" : transfer.getTag ();
414
+
415
+ // Pad for required 27 tryte length
416
+ tag = Type::Utils::rightPad (tag, TryteAlphabetLength, ' 9' );
417
+
418
+ // Add first entry to the bundle
419
+ bundle.addTransaction (signatureMessageLength, transfer.getAddress (), transfer.getValue (), tag,
420
+ timestamp);
421
+ // Sum up total value
422
+ totalValue += transfer.getValue ();
423
+ }
424
+
425
+ // Get inputs if we are sending tokens
426
+ if (totalValue != 0 ) {
427
+ if (!validateInputs)
428
+ return this ->addRemainder (seed, security, inputs, bundle, tag, totalValue, remainder,
429
+ signatureFragments);
430
+ // Case 1: user provided inputs
431
+ // Validate the inputs by calling getBalances
432
+ if (!validateInputs)
433
+ return addRemainder (seed, security, inputs, bundle, tag, totalValue, remainder,
434
+ signatureFragments);
435
+ if (not inputs.empty ()) {
436
+ // Get list if addresses of the provided inputs
437
+ std::vector<std::string> inputsAddresses;
438
+ for (const auto & input : inputs) {
439
+ inputsAddresses.push_back (input.getAddress ());
440
+ }
441
+
442
+ // TODO 100 ?
443
+ auto balancesResponse = this ->getBalances (inputsAddresses, 100 );
444
+ auto balances = balancesResponse.getBalances ();
445
+
446
+ std::vector<input> confirmedInputs;
447
+ int totalBalance = 0 ;
448
+ int i = 0 ;
449
+ for (const auto & balance : balances) {
450
+ long thisBalance = std::stol (balance);
451
+
452
+ // If input has balance, add it to confirmedInputs
453
+ if (thisBalance > 0 ) {
454
+ totalBalance += thisBalance;
455
+ auto inputEl = inputs[i++];
456
+ inputEl.setBalance (thisBalance);
457
+ confirmedInputs.push_back (inputEl);
458
+
459
+ // if we've already reached the intended input value, break out of loop
460
+ if (totalBalance >= totalValue) {
461
+ break ;
462
+ }
463
+ }
464
+ }
465
+
466
+ // Return not enough balance error
467
+ if (totalValue > totalBalance) {
468
+ throw Errors::IllegalState (" Not enough balance" );
469
+ }
470
+
471
+ return this ->addRemainder (seed, security, confirmedInputs, bundle, tag, totalValue, remainder,
472
+ signatureFragments);
473
+ }
474
+
475
+ // Case 2: Get inputs deterministically
476
+ //
477
+ // If no inputs provided, derive the addresses from the seed and
478
+ // confirm that the inputs exceed the threshold
479
+ else {
480
+ auto newinputs = this ->getInputs (seed, security, 0 , 0 , totalValue);
481
+ // If inputs with enough balance
482
+ return addRemainder (seed, security, newinputs.getInput (), bundle, tag, totalValue, remainder,
483
+ signatureFragments);
484
+ }
485
+ } else {
486
+ // If no input required, don't sign and simply finalize the bundle
487
+ auto curl = Crypto::create (this ->cryptoType_ );
488
+ bundle.finalize (curl);
489
+ bundle.addTrytes (signatureFragments);
490
+
491
+ auto trxb = bundle.getTransactions ();
492
+ std::vector<std::string> bundleTrytes;
493
+
494
+ for (const auto & trx : trxb) {
495
+ bundleTrytes.push_back (trx.toTrytes ());
496
+ }
497
+ std::reverse (bundleTrytes.begin (), bundleTrytes.end ());
498
+ return bundleTrytes;
499
+ }
351
500
}
352
501
353
502
getBundleResponse
@@ -469,7 +618,7 @@ Extended::replayTransfer() const {
469
618
470
619
sendTransferResponse
471
620
Extended::sendTransfer (const Type::Trytes& seed, int security, int depth, int minWeightMagnitude,
472
- const std::vector<Transfer>& transfers, const std::vector<input>& inputs,
621
+ std::vector<Transfer>& transfers, const std::vector<input>& inputs,
473
622
const Type::Trytes& address) const {
474
623
// Validate the security level
475
624
if (security < 1 || security > 3 ) {
@@ -578,12 +727,12 @@ Extended::addRemainder(const Type::Trytes& seed, const unsigned int& security,
578
727
const std::vector<input>& inputs, Bundle& bundle, const std::string& tag,
579
728
const long & totalValue, const Type::Trytes& remainderAddress,
580
729
const std::vector<std::string>& signatureFragments) const {
581
- auto totalTransferValue = totalValue;
730
+ Utils::StopWatch sw;
731
+ auto totalTransferValue = totalValue;
582
732
for (const auto & input : inputs) {
583
733
auto thisBalance = input.getBalance ();
584
734
auto toSubtract = -thisBalance;
585
- // TODO std::chrono ?
586
- auto timestamp = std::time (0 );
735
+ long timestamp = sw.now ().count ();
587
736
// Add input as bundle entry
588
737
bundle.addTransaction (input.getSecurity (), input.getAddress (), toSubtract, tag, timestamp);
589
738
// If there is a remainder value
@@ -642,7 +791,8 @@ Extended::replayBundle(const Type::Trytes& transaction, int depth, int minWeight
642
791
643
792
std::vector<Transaction>
644
793
Extended::initiateTransfer (int securitySum, const std::string& inputAddress,
645
- const std::string& remainderAddress, std::vector<Transfer>& transfers) {
794
+ const std::string& remainderAddress,
795
+ std::vector<Transfer>& transfers) const {
646
796
Utils::StopWatch sw;
647
797
Crypto::Checksum checksum;
648
798
@@ -887,7 +1037,7 @@ Extended::signInputsAndReturn(const std::string& seed, const std::vector<input>&
887
1037
}
888
1038
889
1039
bool
890
- Extended::isTransfersCollectionValid (const std::vector<Transfer>& transfers) {
1040
+ Extended::isTransfersCollectionValid (const std::vector<Transfer>& transfers) const {
891
1041
for (const auto & transfer : transfers) {
892
1042
if (!transfer.isValid ()) {
893
1043
return false ;
0 commit comments