Skip to content

Commit 6a7cc8f

Browse files
thibault-martinezCylix
authored andcommitted
prepareTransfers (#124)
1 parent e496f88 commit 6a7cc8f

File tree

5 files changed

+173
-16
lines changed

5 files changed

+173
-16
lines changed

include/API/Extended.hpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -191,9 +191,10 @@ class Extended : public Core {
191191
* @return Returns bundle trytes.
192192
*/
193193
std::vector<Type::Trytes> prepareTransfers(const Type::Trytes& seed, int security,
194-
const std::vector<Transfer>& transfers,
195-
const std::string& remainder,
196-
const std::vector<input>& inputs) const;
194+
std::vector<Transfer>& transfers,
195+
const std::string& remainder,
196+
const std::vector<input>& inputs,
197+
bool validateInputs = true) const;
197198

198199
/*
199200
* This function returns the bundle which is associated with a transaction. Input can by any type
@@ -244,7 +245,7 @@ class Extended : public Core {
244245
* @return Array of Transaction objects.
245246
*/
246247
sendTransferResponse sendTransfer(const Type::Trytes& seed, int security, int depth,
247-
int minWeightMagnitude, const std::vector<Transfer>& transfers,
248+
int minWeightMagnitude, std::vector<Transfer>& transfers,
248249
const std::vector<input>& inputs,
249250
const Type::Trytes& address) const;
250251

@@ -344,7 +345,7 @@ class Extended : public Core {
344345
*/
345346
std::vector<Transaction> initiateTransfer(int securitySum, const Type::Trytes& inputAddress,
346347
const Type::Trytes& remainderAddress,
347-
std::vector<Transfer>& transfers);
348+
std::vector<Transfer>& transfers) const;
348349

349350
private:
350351
/**
@@ -368,7 +369,7 @@ class Extended : public Core {
368369
/**
369370
* @return true if all transfers are valid, false otherwise
370371
*/
371-
bool isTransfersCollectionValid(const std::vector<Transfer>& transfers);
372+
bool isTransfersCollectionValid(const std::vector<Transfer>& transfers) const;
372373

373374
private:
374375
/**

include/Model/input.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class input {
4242
* Balance
4343
*/
4444
const int64_t& getBalance() const;
45+
void setBalance(const int64_t& balance);
4546
/*
4647
* Key Index
4748
*/

source/API/Extended.cpp

Lines changed: 159 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -344,10 +344,159 @@ Extended::getLatestInclusion(const std::vector<Type::Trytes>& hashes) const {
344344
return getInclusionStates(hashes, { getNodeInfo().getLatestSolidSubtangleMilestone() });
345345
}
346346

347+
// TODO Response ?
347348
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+
}
351500
}
352501

353502
getBundleResponse
@@ -469,7 +618,7 @@ Extended::replayTransfer() const {
469618

470619
sendTransferResponse
471620
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,
473622
const Type::Trytes& address) const {
474623
// Validate the security level
475624
if (security < 1 || security > 3) {
@@ -578,12 +727,12 @@ Extended::addRemainder(const Type::Trytes& seed, const unsigned int& security,
578727
const std::vector<input>& inputs, Bundle& bundle, const std::string& tag,
579728
const long& totalValue, const Type::Trytes& remainderAddress,
580729
const std::vector<std::string>& signatureFragments) const {
581-
auto totalTransferValue = totalValue;
730+
Utils::StopWatch sw;
731+
auto totalTransferValue = totalValue;
582732
for (const auto& input : inputs) {
583733
auto thisBalance = input.getBalance();
584734
auto toSubtract = -thisBalance;
585-
// TODO std::chrono ?
586-
auto timestamp = std::time(0);
735+
long timestamp = sw.now().count();
587736
// Add input as bundle entry
588737
bundle.addTransaction(input.getSecurity(), input.getAddress(), toSubtract, tag, timestamp);
589738
// If there is a remainder value
@@ -642,7 +791,8 @@ Extended::replayBundle(const Type::Trytes& transaction, int depth, int minWeight
642791

643792
std::vector<Transaction>
644793
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 {
646796
Utils::StopWatch sw;
647797
Crypto::Checksum checksum;
648798

@@ -887,7 +1037,7 @@ Extended::signInputsAndReturn(const std::string& seed, const std::vector<input>&
8871037
}
8881038

8891039
bool
890-
Extended::isTransfersCollectionValid(const std::vector<Transfer>& transfers) {
1040+
Extended::isTransfersCollectionValid(const std::vector<Transfer>& transfers) const {
8911041
for (const auto& transfer : transfers) {
8921042
if (!transfer.isValid()) {
8931043
return false;

source/Model/input.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ input::getBalance() const {
4343
return this->balance_;
4444
}
4545

46+
void
47+
input::setBalance(const int64_t& balance) {
48+
this->balance_ = balance;
49+
}
50+
4651
const int32_t&
4752
input::getKeyIndex() const {
4853
return this->keyIndex_;

source/Type/utils.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ namespace Utils {
3737
std::string
3838
rightPad(const std::string& s, std::size_t padLen, char padChar) {
3939
std::stringstream ss;
40-
ss << std::setfill(padChar) << std::setw(padLen);
40+
ss << std::setfill(padChar) << std::setw(padLen) << s;
4141

4242
return ss.str();
4343
}

0 commit comments

Comments
 (0)