From 6be97727ad2ce8db956974ddbd4fa7190bc02cff Mon Sep 17 00:00:00 2001 From: dexX7 Date: Thu, 30 Jul 2015 01:56:00 +0200 Subject: [PATCH 01/12] Add "send all" transaction type --- src/omnicore/createpayload.cpp | 14 +++++ src/omnicore/createpayload.h | 1 + src/omnicore/omnicore.h | 2 + src/omnicore/rpctx.cpp | 53 ++++++++++++++++++ src/omnicore/rpctxobject.cpp | 8 +++ src/omnicore/rpctxobject.h | 1 + src/omnicore/rules.cpp | 5 ++ src/omnicore/rules.h | 2 + src/omnicore/test/create_payload_tests.cpp | 8 +++ src/omnicore/tx.cpp | 63 ++++++++++++++++++++++ src/omnicore/tx.h | 2 + src/qt/txhistorydialog.cpp | 1 + 12 files changed, 160 insertions(+) diff --git a/src/omnicore/createpayload.cpp b/src/omnicore/createpayload.cpp index 03d9394e87fb..8b3fbe59875f 100644 --- a/src/omnicore/createpayload.cpp +++ b/src/omnicore/createpayload.cpp @@ -43,6 +43,20 @@ std::vector CreatePayload_SimpleSend(uint32_t propertyId, uint64_ return payload; } +std::vector CreatePayload_SendAll() +{ + std::vector payload; + uint16_t messageType = 4; + uint16_t messageVer = 0; + mastercore::swapByteOrder16(messageType); + mastercore::swapByteOrder16(messageVer); + + PUSH_BACK_BYTES(payload, messageVer); + PUSH_BACK_BYTES(payload, messageType); + + return payload; +} + std::vector CreatePayload_DExSell(uint32_t propertyId, uint64_t amountForSale, uint64_t amountDesired, uint8_t timeLimit, uint64_t minFee, uint8_t subAction) { std::vector payload; diff --git a/src/omnicore/createpayload.h b/src/omnicore/createpayload.h index a838f3f04a2a..a5b9fb8d7e6b 100644 --- a/src/omnicore/createpayload.h +++ b/src/omnicore/createpayload.h @@ -6,6 +6,7 @@ #include std::vector CreatePayload_SimpleSend(uint32_t propertyId, uint64_t amount); +std::vector CreatePayload_SendAll(); std::vector CreatePayload_DExSell(uint32_t propertyId, uint64_t amountForSale, uint64_t amountDesired, uint8_t timeLimit, uint64_t minFee, uint8_t subAction); std::vector CreatePayload_DExAccept(uint32_t propertyId, uint64_t amount); std::vector CreatePayload_SendToOwners(uint32_t propertyId, uint64_t amount); diff --git a/src/omnicore/omnicore.h b/src/omnicore/omnicore.h index dc777b689113..eec8769dff6d 100644 --- a/src/omnicore/omnicore.h +++ b/src/omnicore/omnicore.h @@ -66,6 +66,7 @@ enum TransactionType { MSC_TYPE_SIMPLE_SEND = 0, MSC_TYPE_RESTRICTED_SEND = 2, MSC_TYPE_SEND_TO_OWNERS = 3, + MSC_TYPE_SEND_ALL = 4, MSC_TYPE_SAVINGS_MARK = 10, MSC_TYPE_SAVINGS_COMPROMISED = 11, MSC_TYPE_RATELIMITED_MARK = 12, @@ -123,6 +124,7 @@ enum FILETYPES { #define PKT_ERROR_METADEX (-80000) #define METADEX_ERROR (-81000) #define PKT_ERROR_TOKENS (-82000) +#define PKT_ERROR_SEND_ALL (-83000) #define OMNI_PROPERTY_BTC 0 #define OMNI_PROPERTY_MSC 1 diff --git a/src/omnicore/rpctx.cpp b/src/omnicore/rpctx.cpp index 78862e4b9983..6d3c60c1027c 100644 --- a/src/omnicore/rpctx.cpp +++ b/src/omnicore/rpctx.cpp @@ -93,6 +93,59 @@ Value omni_send(const Array& params, bool fHelp) } } +// omni_sendall - send all +Value omni_sendall(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 2 || params.size() > 4) + throw runtime_error( + "omni_sendall \"fromaddress\" \"toaddress\" ( \"redeemaddress\" \"referenceamount\" )\n" + + "\nTransfers *all* tokens owned to the recipient.\n" + + "\nArguments:\n" + "1. fromaddress (string, required) the address to send from\n" + "2. toaddress (string, required) the address of the receiver\n" + "3. redeemaddress (string, optional) an address that can spent the transaction dust (sender by default)\n" + "4. referenceamount (string, optional) a bitcoin amount that is sent to the receiver (minimal by default)\n" + + "\nResult:\n" + "\"hash\" (string) the hex-encoded transaction hash\n" + + "\nExamples:\n" + + HelpExampleCli("omni_sendall", "\"3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY\" \"37FaKponF7zqoMLUjEiko25pDiuVH5YLEa\"") + + HelpExampleRpc("omni_sendall", "\"3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY\", \"37FaKponF7zqoMLUjEiko25pDiuVH5YLEa\"") + ); + + // obtain parameters & info + std::string fromAddress = ParseAddress(params[0]); + std::string toAddress = ParseAddress(params[1]); + std::string redeemAddress = (params.size() > 2 && !ParseText(params[2]).empty()) ? ParseAddress(params[2]): ""; + int64_t referenceAmount = (params.size() > 3) ? ParseAmount(params[3], true): 0; + + // perform checks + RequireSaneReferenceAmount(referenceAmount); + + // create a payload for the transaction + std::vector payload = CreatePayload_SendAll(); + + // request the wallet build the transaction (and if needed commit it) + uint256 txid; + std::string rawHex; + int result = ClassAgnosticWalletTXBuilder(fromAddress, toAddress, redeemAddress, referenceAmount, payload, txid, rawHex, autoCommit); + + // check error and return the txid (or raw hex depending on autocommit) + if (result != 0) { + throw JSONRPCError(result, error_str(result)); + } else { + if (!autoCommit) { + return rawHex; + } else { + // TODO: pending + return txid.GetHex(); + } + } +} + // omni_senddexsell - DEx sell offer Value omni_senddexsell(const Array& params, bool fHelp) { diff --git a/src/omnicore/rpctxobject.cpp b/src/omnicore/rpctxobject.cpp index 58ec75f84e91..8ad600688074 100644 --- a/src/omnicore/rpctxobject.cpp +++ b/src/omnicore/rpctxobject.cpp @@ -139,6 +139,9 @@ void populateRPCTypeInfo(CMPTransaction& mp_obj, Object& txobj, uint32_t txType, case MSC_TYPE_SEND_TO_OWNERS: populateRPCTypeSendToOwners(mp_obj, txobj, extendedDetails, extendedDetailsFilter); break; + case MSC_TYPE_SEND_ALL: + populateRPCTypeSendAll(mp_obj, txobj); + break; case MSC_TYPE_TRADE_OFFER: populateRPCTypeTradeOffer(mp_obj, txobj); break; @@ -243,6 +246,11 @@ void populateRPCTypeSendToOwners(CMPTransaction& omniObj, Object& txobj, bool ex if (extendedDetails) populateRPCExtendedTypeSendToOwners(omniObj.getHash(), extendedDetailsFilter, txobj); } +void populateRPCTypeSendAll(CMPTransaction& omniObj, Object& txobj) +{ + // TODO: list all recipients? +} + void populateRPCTypeTradeOffer(CMPTransaction& omniObj, Object& txobj) { CMPOffer temp_offer(omniObj); diff --git a/src/omnicore/rpctxobject.h b/src/omnicore/rpctxobject.h index 700a2f83b490..74797d107a06 100644 --- a/src/omnicore/rpctxobject.h +++ b/src/omnicore/rpctxobject.h @@ -14,6 +14,7 @@ void populateRPCTypeInfo(CMPTransaction& mp_obj, json_spirit::Object& txobj, uin void populateRPCTypeSimpleSend(CMPTransaction& omniObj, json_spirit::Object& txobj); void populateRPCTypeSendToOwners(CMPTransaction& omniObj, json_spirit::Object& txobj, bool extendedDetails, std::string extendedDetailsFilter); +void populateRPCTypeSendAll(CMPTransaction& omniObj, json_spirit::Object& txobj); void populateRPCTypeTradeOffer(CMPTransaction& omniObj, json_spirit::Object& txobj); void populateRPCTypeMetaDExTrade(CMPTransaction& omniObj, json_spirit::Object& txobj, bool extendedDetails); void populateRPCTypeMetaDExCancelPrice(CMPTransaction& omniObj, json_spirit::Object& txobj, bool extendedDetails); diff --git a/src/omnicore/rules.cpp b/src/omnicore/rules.cpp index fee541b72fa6..c2e74b1385af 100644 --- a/src/omnicore/rules.cpp +++ b/src/omnicore/rules.cpp @@ -57,6 +57,8 @@ std::vector CConsensusParams::GetRestrictions() const { MSC_TYPE_METADEX_CANCEL_PAIR, MP_TX_PKT_V0, false, MSC_METADEX_BLOCK }, { MSC_TYPE_METADEX_CANCEL_ECOSYSTEM, MP_TX_PKT_V0, true, MSC_METADEX_BLOCK }, + { MSC_TYPE_SEND_ALL, MP_TX_PKT_V0, true, MSC_SEND_ALL_BLOCK }, + { MSC_TYPE_OFFER_ACCEPT_A_BET, MP_TX_PKT_V0, false, MSC_BET_BLOCK }, }; @@ -144,6 +146,7 @@ CMainConsensusParams::CMainConsensusParams() MSC_MANUALSP_BLOCK = 323230; MSC_STO_BLOCK = 342650; MSC_METADEX_BLOCK = 999999; + MSC_SEND_ALL_BLOCK = 999999; MSC_BET_BLOCK = 999999; // Other feature activations: GRANTEFFECTS_FEATURE_BLOCK = 999999; @@ -177,6 +180,7 @@ CTestNetConsensusParams::CTestNetConsensusParams() MSC_MANUALSP_BLOCK = 0; MSC_STO_BLOCK = 0; MSC_METADEX_BLOCK = 0; + MSC_SEND_ALL_BLOCK = 0; MSC_BET_BLOCK = 999999; // Other feature activations: GRANTEFFECTS_FEATURE_BLOCK = 999999; @@ -210,6 +214,7 @@ CRegTestConsensusParams::CRegTestConsensusParams() MSC_MANUALSP_BLOCK = 0; MSC_STO_BLOCK = 0; MSC_METADEX_BLOCK = 0; + MSC_SEND_ALL_BLOCK = 0; MSC_BET_BLOCK = 999999; // Other feature activations: GRANTEFFECTS_FEATURE_BLOCK = 999999; diff --git a/src/omnicore/rules.h b/src/omnicore/rules.h index aaa854e973ae..8498382306a9 100644 --- a/src/omnicore/rules.h +++ b/src/omnicore/rules.h @@ -96,6 +96,8 @@ class CConsensusParams int MSC_STO_BLOCK; //! Block to enable MetaDEx transactions int MSC_METADEX_BLOCK; + //! Block to enable "send all" transactions + int MSC_SEND_ALL_BLOCK; //! Block to enable betting transactions int MSC_BET_BLOCK; diff --git a/src/omnicore/test/create_payload_tests.cpp b/src/omnicore/test/create_payload_tests.cpp index e926249c1b79..8939e9a89931 100644 --- a/src/omnicore/test/create_payload_tests.cpp +++ b/src/omnicore/test/create_payload_tests.cpp @@ -30,6 +30,14 @@ BOOST_AUTO_TEST_CASE(payload_send_to_owners) BOOST_CHECK_EQUAL(HexStr(vch), "00000003000000010000000005f5e100"); } +BOOST_AUTO_TEST_CASE(payload_send_all) +{ + // Send to owners [type 4, version 0] + std::vector vch = CreatePayload_SendAll(); + + BOOST_CHECK_EQUAL(HexStr(vch), "00000004"); +} + BOOST_AUTO_TEST_CASE(payload_dex_offer) { // Sell tokens for bitcoins [type 20, version 1] diff --git a/src/omnicore/tx.cpp b/src/omnicore/tx.cpp index 65fb128c9740..fd8de376fbca 100644 --- a/src/omnicore/tx.cpp +++ b/src/omnicore/tx.cpp @@ -39,6 +39,7 @@ std::string mastercore::strTransactionType(uint16_t txType) case MSC_TYPE_SIMPLE_SEND: return "Simple Send"; case MSC_TYPE_RESTRICTED_SEND: return "Restricted Send"; case MSC_TYPE_SEND_TO_OWNERS: return "Send To Owners"; + case MSC_TYPE_SEND_ALL: return "Send All"; case MSC_TYPE_SAVINGS_MARK: return "Savings"; case MSC_TYPE_SAVINGS_COMPROMISED: return "Savings COMPROMISED"; case MSC_TYPE_RATELIMITED_MARK: return "Rate-Limiting"; @@ -104,6 +105,9 @@ bool CMPTransaction::interpret_Transaction() case MSC_TYPE_SEND_TO_OWNERS: return interpret_SendToOwners(); + case MSC_TYPE_SEND_ALL: + return interpret_SendAll(); + case MSC_TYPE_TRADE_OFFER: return interpret_TradeOffer(); @@ -217,6 +221,16 @@ bool CMPTransaction::interpret_SendToOwners() return true; } +/** Tx 4 */ +bool CMPTransaction::interpret_SendAll() +{ + if (pkt_size < 4) { + return false; + } + + return true; +} + /** Tx 20 */ bool CMPTransaction::interpret_TradeOffer() { @@ -661,6 +675,9 @@ int CMPTransaction::interpretPacket() case MSC_TYPE_SEND_TO_OWNERS: return logicMath_SendToOwners(); + case MSC_TYPE_SEND_ALL: + return logicMath_SendAll(); + case MSC_TYPE_TRADE_OFFER: return logicMath_TradeOffer(); @@ -950,6 +967,52 @@ int CMPTransaction::logicMath_SendToOwners() return 0; } +/** Tx 4 */ +int CMPTransaction::logicMath_SendAll() +{ + if (!IsTransactionTypeAllowed(block, property, type, version)) { + PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", + __func__, + type, + version, + property, + block); + return (PKT_ERROR_SEND_ALL -22); + } + + // ------------------------------------------ + + // Special case: if can't find the receiver -- assume send to self! + if (receiver.empty()) { + receiver = sender; + } + + CMPTally* ptally = getTally(sender); + if (ptally == NULL) { + PrintToLog("%s(): rejected: sender %s has no tokens to send\n", __func__, sender); + return (PKT_ERROR_SEND_ALL -54); + } + + bool fSent = false; + uint32_t propertyId = ptally->init(); + + while (0 != (propertyId = ptally->next())) { + int64_t money = ptally->getMoney(propertyId, BALANCE); + if (money > 0) { + fSent = true; + assert(update_tally_map(sender, propertyId, -money, BALANCE)); + assert(update_tally_map(receiver, propertyId, money, BALANCE)); + } + } + + if (!fSent) { + PrintToLog("%s(): rejected: sender %s has no tokens to send\n", __func__, sender); + return (PKT_ERROR_SEND_ALL -55); + } + + return 0; +} + /** Tx 20 */ int CMPTransaction::logicMath_TradeOffer() { diff --git a/src/omnicore/tx.h b/src/omnicore/tx.h index 4c4e9ccca993..8a068dddb894 100644 --- a/src/omnicore/tx.h +++ b/src/omnicore/tx.h @@ -99,6 +99,7 @@ class CMPTransaction bool interpret_TransactionType(); bool interpret_SimpleSend(); bool interpret_SendToOwners(); + bool interpret_SendAll(); bool interpret_TradeOffer(); bool interpret_MetaDExTrade(); bool interpret_MetaDExCancelPrice(); @@ -120,6 +121,7 @@ class CMPTransaction */ int logicMath_SimpleSend(); int logicMath_SendToOwners(); + int logicMath_SendAll(); int logicMath_TradeOffer(); int logicMath_AcceptOffer_BTC(); int logicMath_MetaDExTrade(); diff --git a/src/qt/txhistorydialog.cpp b/src/qt/txhistorydialog.cpp index 4ccfbf35dbab..7cf36522c80b 100644 --- a/src/qt/txhistorydialog.cpp +++ b/src/qt/txhistorydialog.cpp @@ -503,6 +503,7 @@ std::string TXHistoryDialog::shrinkTxType(int txType, bool *fundsMoved) case MSC_TYPE_SIMPLE_SEND: displayType = "Send"; break; case MSC_TYPE_RESTRICTED_SEND: displayType = "Rest. Send"; break; case MSC_TYPE_SEND_TO_OWNERS: displayType = "Send To Owners"; break; + case MSC_TYPE_SEND_ALL: displayType = "Send All"; break; case MSC_TYPE_SAVINGS_MARK: displayType = "Mark Savings"; *fundsMoved = false; break; case MSC_TYPE_SAVINGS_COMPROMISED: ; displayType = "Lock Savings"; break; case MSC_TYPE_RATELIMITED_MARK: displayType = "Rate Limit"; break; From a0c096d39242fb029749649d3ee979112d9a5202 Mon Sep 17 00:00:00 2001 From: zathras-crypto Date: Thu, 30 Jul 2015 11:26:27 +1000 Subject: [PATCH 02/12] Rename getNumberOfPurchases() to getNumberOfSubRecords() Note: this is a semantical change only to permit reuse of txlistdb subrecord logic for send all --- src/omnicore/omnicore.cpp | 17 ++++++----------- src/omnicore/omnicore.h | 2 +- src/omnicore/rpctxobject.cpp | 2 +- src/qt/overviewpage.cpp | 2 +- src/qt/txhistorydialog.cpp | 2 +- 5 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/omnicore/omnicore.cpp b/src/omnicore/omnicore.cpp index eaf2540ea98a..6ad0bf1ec19d 100644 --- a/src/omnicore/omnicore.cpp +++ b/src/omnicore/omnicore.cpp @@ -3111,24 +3111,19 @@ int CMPTxList::getNumberOfMetaDExCancels(const uint256 txid) return numberOfCancels; } -int CMPTxList::getNumberOfPurchases(const uint256 txid) +int CMPTxList::getNumberOfSubRecords(const uint256 txid) { if (!pdb) return 0; - int numberOfPurchases = 0; + int numberOfSubRecords = 0; std::vector vstr; string strValue; Status status = pdb->Get(readoptions, txid.ToString(), &strValue); - if (status.ok()) - { - // parse the string returned + if (status.ok()) { + // parse the string returned & obtain the number of sub records boost::split(vstr, strValue, boost::is_any_of(":"), token_compress_on); - // obtain the number of purchases - if (4 <= vstr.size()) - { - numberOfPurchases = atoi(vstr[3]); - } + if (4 <= vstr.size()) numberOfSubRecords = atoi(vstr[3]); } - return numberOfPurchases; + return numberOfSubRecords; } int CMPTxList::getMPTransactionCountTotal() diff --git a/src/omnicore/omnicore.h b/src/omnicore/omnicore.h index eec8769dff6d..0a876d210324 100644 --- a/src/omnicore/omnicore.h +++ b/src/omnicore/omnicore.h @@ -227,7 +227,7 @@ class CMPTxList : public CDBBase string getKeyValue(string key); uint256 findMetaDExCancel(const uint256 txid); - int getNumberOfPurchases(const uint256 txid); + int getNumberOfSubRecords(const uint256 txid); int getNumberOfMetaDExCancels(const uint256 txid); bool getPurchaseDetails(const uint256 txid, int purchaseNumber, string *buyer, string *seller, uint64_t *vout, uint64_t *propertyId, uint64_t *nValue); int getMPTransactionCountTotal(); diff --git a/src/omnicore/rpctxobject.cpp b/src/omnicore/rpctxobject.cpp index 8ad600688074..da48a04adf62 100644 --- a/src/omnicore/rpctxobject.cpp +++ b/src/omnicore/rpctxobject.cpp @@ -536,7 +536,7 @@ int populateRPCDExPurchases(const CTransaction& wtx, Array& purchases, std::stri int numberOfPurchases = 0; { LOCK(cs_tally); - numberOfPurchases = p_txlistdb->getNumberOfPurchases(wtx.GetHash()); + numberOfPurchases = p_txlistdb->getNumberOfSubRecords(wtx.GetHash()); } if (numberOfPurchases <= 0) { PrintToLog("TXLISTDB Error: Transaction %s parsed as a DEx payment but could not locate purchases in txlistdb.\n", wtx.GetHash().GetHex()); diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index c9e0200b728c..93a3bb2c4ee7 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -166,7 +166,7 @@ class TxViewDelegate : public QAbstractItemDelegate } bool bIsBuy = IsMyAddress(tmpBuyer); LOCK(cs_tally); - int numberOfPurchases=p_txlistdb->getNumberOfPurchases(hash); + int numberOfPurchases=p_txlistdb->getNumberOfSubRecords(hash); if (0getPurchaseDetails(hash,purchaseNumber,&tmpBuyer,&tmpSeller,&tmpVout,&tmpPropertyId,&tmpNValue); diff --git a/src/qt/txhistorydialog.cpp b/src/qt/txhistorydialog.cpp index 7cf36522c80b..2b967400a3d9 100644 --- a/src/qt/txhistorydialog.cpp +++ b/src/qt/txhistorydialog.cpp @@ -272,7 +272,7 @@ int TXHistoryDialog::PopulateHistoryMap() p_txlistdb->getPurchaseDetails(txHash, 1, &tmpBuyer, &tmpSeller, &tmpVout, &tmpPropertyId, &tmpNValue); } bIsBuy = IsMyAddress(tmpBuyer); - numberOfPurchases = p_txlistdb->getNumberOfPurchases(txHash); + numberOfPurchases = p_txlistdb->getNumberOfSubRecords(txHash); if (0 >= numberOfPurchases) continue; for (int purchaseNumber = 1; purchaseNumber <= numberOfPurchases; purchaseNumber++) { LOCK(cs_tally); From 73e36b158abe783be6cd1d428e6276444700338c Mon Sep 17 00:00:00 2001 From: zathras-crypto Date: Thu, 30 Jul 2015 11:49:54 +1000 Subject: [PATCH 03/12] Record number of sub sends --- src/omnicore/tx.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/omnicore/tx.cpp b/src/omnicore/tx.cpp index fd8de376fbca..0ba03f1fbfda 100644 --- a/src/omnicore/tx.cpp +++ b/src/omnicore/tx.cpp @@ -995,11 +995,13 @@ int CMPTransaction::logicMath_SendAll() bool fSent = false; uint32_t propertyId = ptally->init(); + int numberOfPropertiesSent = 0; while (0 != (propertyId = ptally->next())) { int64_t money = ptally->getMoney(propertyId, BALANCE); if (money > 0) { fSent = true; + numberOfPropertiesSent++; assert(update_tally_map(sender, propertyId, -money, BALANCE)); assert(update_tally_map(receiver, propertyId, money, BALANCE)); } @@ -1010,6 +1012,8 @@ int CMPTransaction::logicMath_SendAll() return (PKT_ERROR_SEND_ALL -55); } + nNewValue = numberOfPropertiesSent; + return 0; } From ae3d8b60d8a4fac5d8f9a36a5dfa48232a014b08 Mon Sep 17 00:00:00 2001 From: zathras-crypto Date: Thu, 30 Jul 2015 12:06:54 +1000 Subject: [PATCH 04/12] Add recordSendAllSubRecord() to CMPTxList --- src/omnicore/omnicore.cpp | 11 +++++++++++ src/omnicore/omnicore.h | 1 + 2 files changed, 12 insertions(+) diff --git a/src/omnicore/omnicore.cpp b/src/omnicore/omnicore.cpp index 6ad0bf1ec19d..958eba85c0b2 100644 --- a/src/omnicore/omnicore.cpp +++ b/src/omnicore/omnicore.cpp @@ -3248,6 +3248,17 @@ void CMPTxList::recordMetaDExCancelTX(const uint256 &txidMaster, const uint256 & } } +void CMPTxList::recordSendAllSubRecord(const uint256& txid, int subRecordNumber, uint32_t propertyId, int64_t nValue) +{ + if (!pdb) return; + + const std::string& key = strprintf("%s-%d", txid.ToString(), subRecordNumber); + const std::string& value = strprintf("%d:%d", propertyId, nValue); + + Status status = pdb->Put(writeoptions, key, value); + if (msc_debug_txdb) PrintToLog("%s(): Key:%s, Value:%s, Status:%s\n", __FUNCTION__, key, value, status.ToString()); +} + void CMPTxList::recordPaymentTX(const uint256 &txid, bool fValid, int nBlock, unsigned int vout, unsigned int propertyId, uint64_t nValue, string buyer, string seller) { if (!pdb) return; diff --git a/src/omnicore/omnicore.h b/src/omnicore/omnicore.h index 0a876d210324..8317b6e2ae37 100644 --- a/src/omnicore/omnicore.h +++ b/src/omnicore/omnicore.h @@ -224,6 +224,7 @@ class CMPTxList : public CDBBase void recordTX(const uint256 &txid, bool fValid, int nBlock, unsigned int type, uint64_t nValue); void recordPaymentTX(const uint256 &txid, bool fValid, int nBlock, unsigned int vout, unsigned int propertyId, uint64_t nValue, string buyer, string seller); void recordMetaDExCancelTX(const uint256 &txidMaster, const uint256 &txidSub, bool fValid, int nBlock, unsigned int propertyId, uint64_t nValue); + void recordSendAllSubRecord(const uint256& txid, int subRecordNumber, uint32_t propertyId, int64_t nvalue); string getKeyValue(string key); uint256 findMetaDExCancel(const uint256 txid); From 7300667b1ca1e423e0400caedbb9b746b26e36b6 Mon Sep 17 00:00:00 2001 From: zathras-crypto Date: Thu, 30 Jul 2015 15:01:27 +1000 Subject: [PATCH 05/12] Activate recording of sub sends for send all --- src/omnicore/tx.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/omnicore/tx.cpp b/src/omnicore/tx.cpp index 0ba03f1fbfda..c0166c6b7f89 100644 --- a/src/omnicore/tx.cpp +++ b/src/omnicore/tx.cpp @@ -1004,6 +1004,7 @@ int CMPTransaction::logicMath_SendAll() numberOfPropertiesSent++; assert(update_tally_map(sender, propertyId, -money, BALANCE)); assert(update_tally_map(receiver, propertyId, money, BALANCE)); + p_txlistdb->recordSendAllSubRecord(txid, numberOfPropertiesSent, propertyId, money); } } From d910c04dcfad063ac18c566d35ad2c45de64abd8 Mon Sep 17 00:00:00 2001 From: zathras-crypto Date: Thu, 30 Jul 2015 15:18:45 +1000 Subject: [PATCH 06/12] Add omni_sendall to RPC server --- src/rpcserver.cpp | 1 + src/rpcserver.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 124a5c5a4462..8081b93e2b74 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -400,6 +400,7 @@ static const CRPCCommand vRPCCommands[] = { "omni layer (transaction creation)", "omni_sendrevoke", &omni_sendrevoke, false, true, true }, { "omni layer (transaction creation)", "omni_sendclosecrowdsale", &omni_sendclosecrowdsale, false, true, true }, { "omni layer (transaction creation)", "omni_sendchangeissuer", &omni_sendchangeissuer, false, true, true }, + { "omni layer (transaction creation)", "omni_sendall", &omni_sendall, false, true, true }, /* Omni Core hidden calls - development usage (not shown in help) */ /* CATEGORY NAME ACTOR (FUNCTION) OKSAFEMODE THREADSAFE REQWALLET */ diff --git a/src/rpcserver.h b/src/rpcserver.h index 66bfb4c24bb9..7d981f0ea439 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -267,6 +267,7 @@ extern json_spirit::Value omni_sendgrant(const json_spirit::Array& params, bool extern json_spirit::Value omni_sendrevoke(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value omni_sendclosecrowdsale(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value omni_sendchangeissuer(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value omni_sendall(const json_spirit::Array& params, bool fHelp); /* Omni Core hidden calls - development usage (not shown in help) */ extern json_spirit::Value mscrpc(const json_spirit::Array& params, bool fHelp); From e549cf9bbdd974160e80556fcfcc5eb7d9e2af32 Mon Sep 17 00:00:00 2001 From: zathras-crypto Date: Thu, 30 Jul 2015 15:33:05 +1000 Subject: [PATCH 07/12] Add getSendAllDetails() to CMPTxList Fix incorrect expectation of element size --- src/omnicore/omnicore.cpp | 17 +++++++++++++++++ src/omnicore/omnicore.h | 1 + 2 files changed, 18 insertions(+) diff --git a/src/omnicore/omnicore.cpp b/src/omnicore/omnicore.cpp index 958eba85c0b2..a40ae4e3dc58 100644 --- a/src/omnicore/omnicore.cpp +++ b/src/omnicore/omnicore.cpp @@ -3172,6 +3172,23 @@ string CMPTxList::getKeyValue(string key) if (status.ok()) { return strValue; } else { return ""; } } +bool CMPTxList::getSendAllDetails(const uint256& txid, int subSend, uint32_t *propertyId, int64_t *amount) +{ + if (!pdb) return 0; + std::vector vstr; + string strValue; + Status status = pdb->Get(readoptions, txid.ToString()+"-"+to_string(subSend), &strValue); + if (status.ok()) { + boost::split(vstr, strValue, boost::is_any_of(":"), token_compress_on); + if (2 == vstr.size()) { + *propertyId = atoi(vstr[0]); + *amount = boost::lexical_cast(vstr[1]);; + return true; + } + } + return false; +} + bool CMPTxList::getPurchaseDetails(const uint256 txid, int purchaseNumber, string *buyer, string *seller, uint64_t *vout, uint64_t *propertyId, uint64_t *nValue) { if (!pdb) return 0; diff --git a/src/omnicore/omnicore.h b/src/omnicore/omnicore.h index 8317b6e2ae37..3b91753073dd 100644 --- a/src/omnicore/omnicore.h +++ b/src/omnicore/omnicore.h @@ -231,6 +231,7 @@ class CMPTxList : public CDBBase int getNumberOfSubRecords(const uint256 txid); int getNumberOfMetaDExCancels(const uint256 txid); bool getPurchaseDetails(const uint256 txid, int purchaseNumber, string *buyer, string *seller, uint64_t *vout, uint64_t *propertyId, uint64_t *nValue); + bool getSendAllDetails(const uint256& txid, int subSend, uint32_t *propertyId, int64_t *amount); int getMPTransactionCountTotal(); int getMPTransactionCountBlock(int block); From 2d4a0f03352bd63e99db39f6f361e961ca218c5e Mon Sep 17 00:00:00 2001 From: zathras-crypto Date: Thu, 30 Jul 2015 15:55:43 +1000 Subject: [PATCH 08/12] Add RPC code for send all tx type --- src/omnicore/rpctxobject.cpp | 34 +++++++++++++++++++++++++++++++++- src/omnicore/rpctxobject.h | 2 ++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/omnicore/rpctxobject.cpp b/src/omnicore/rpctxobject.cpp index da48a04adf62..59c0ef066ef1 100644 --- a/src/omnicore/rpctxobject.cpp +++ b/src/omnicore/rpctxobject.cpp @@ -204,6 +204,7 @@ bool showRefForTx(uint32_t txType) case MSC_TYPE_GRANT_PROPERTY_TOKENS: return true; case MSC_TYPE_REVOKE_PROPERTY_TOKENS: return false; case MSC_TYPE_CHANGE_ISSUER_ADDRESS: return true; + case MSC_TYPE_SEND_ALL: return true; } return true; // default to true, shouldn't be needed but just in case } @@ -248,7 +249,8 @@ void populateRPCTypeSendToOwners(CMPTransaction& omniObj, Object& txobj, bool ex void populateRPCTypeSendAll(CMPTransaction& omniObj, Object& txobj) { - // TODO: list all recipients? + Array subSends; + if (populateRPCSendAllSubSends(omniObj.getHash(), subSends) > 0) txobj.push_back(Pair("subsends", subSends)); } void populateRPCTypeTradeOffer(CMPTransaction& omniObj, Object& txobj) @@ -527,6 +529,36 @@ void populateRPCExtendedTypeMetaDExCancel(const uint256& txid, Object& txobj) txobj.push_back(Pair("cancelledtransactions", cancelArray)); } +/* Function to enumerate sub sends for a given txid and add to supplied JSON array + * Note: this function exists as send all has the potential to carry multiple sends in a single transaction. + */ +int populateRPCSendAllSubSends(const uint256& txid, Array& subSends) +{ + int numberOfSubSends = 0; + { + LOCK(cs_tally); + numberOfSubSends = p_txlistdb->getNumberOfSubRecords(txid); + } + if (numberOfSubSends <= 0) { + PrintToLog("TXLISTDB Error: Transaction %s parsed as a send all but could not locate sub sends in txlistdb.\n", txid.GetHex()); + return -1; + } + for (int subSend = 1; subSend <= numberOfSubSends; subSend++) { + Object subSendObj; + uint32_t propertyId; + int64_t amount; + { + LOCK(cs_tally); + p_txlistdb->getSendAllDetails(txid, subSend, &propertyId, &amount); + } + subSendObj.push_back(Pair("propertyid", (uint64_t)propertyId)); + subSendObj.push_back(Pair("divisible", isPropertyDivisible(propertyId))); + subSendObj.push_back(Pair("amount", FormatMP(propertyId, amount))); + subSends.push_back(subSendObj); + } + return subSends.size(); +} + /* Function to enumerate DEx purchases for a given txid and add to supplied JSON array * Note: this function exists as it is feasible for a single transaction to carry multiple outputs * and thus make multiple purchases from a single transaction diff --git a/src/omnicore/rpctxobject.h b/src/omnicore/rpctxobject.h index 74797d107a06..4d3c2b17aae9 100644 --- a/src/omnicore/rpctxobject.h +++ b/src/omnicore/rpctxobject.h @@ -34,6 +34,8 @@ void populateRPCExtendedTypeMetaDExTrade(const uint256& txid, uint32_t propertyI void populateRPCExtendedTypeMetaDExCancel(const uint256& txid, json_spirit::Object& txobj); int populateRPCDExPurchases(const CTransaction& wtx, json_spirit::Array& purchases, std::string filterAddress); +int populateRPCSendAllSubSends(const uint256& txid, json_spirit::Array& subSends); + bool showRefForTx(uint32_t txType); #endif // OMNICORE_RPCTXOBJECT_H From d6acb32d6f0a314d1e440e6097003f458a48b4b4 Mon Sep 17 00:00:00 2001 From: dexX7 Date: Thu, 30 Jul 2015 12:08:20 +0200 Subject: [PATCH 09/12] Fix typo in RPC help, add "omni_sendall" RPC API documentation --- src/omnicore/doc/rpc-api.md | 21 +++++++++++++++++++-- src/omnicore/rpctx.cpp | 6 +++--- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/omnicore/doc/rpc-api.md b/src/omnicore/doc/rpc-api.md index fecd4bac2580..49591f40ca24 100644 --- a/src/omnicore/doc/rpc-api.md +++ b/src/omnicore/doc/rpc-api.md @@ -152,7 +152,7 @@ Create new tokens with manageable supply. 1. ***fromaddress (string, required):*** the address to send from 2. ***propertyid (number, required):*** the identifier of the tokens to distribute 3. ***amount (string, required):*** the amount to distribute -4. ***redeemaddress (string, optional):*** an address that can spent the transaction dust (sender by default) +4. ***redeemaddress (string, optional):*** an address that can spend the transaction dust (sender by default) **Example:** @@ -293,6 +293,23 @@ Change the issuer on record of the given tokens. $ omnicore-cli "omni_sendchangeissuer" "1ARjWDkZ7kT9fwjPrjcQyvbXDkEySzKHwu" "3HTHRxu3aSDV4deakjC7VmsiUp7c6dfbvs" 3 ``` +### omni_sendall + +Transfers *all* tokens owned to the recipient. + +**Arguments:** + +1. ***fromaddress (string, required):*** the address to send from +2. ***toaddress (string, required):*** the address of the receiver +3. ***redeemaddress (string, optional):*** an address that can spend the transaction dust (sender by default) +4. ***referenceamount (string, optional):*** a bitcoin amount that is sent to the receiver (minimal by default) + +**Example:** + +```bash +$ omnicore-cli "omni_sendall" "3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY" "37FaKponF7zqoMLUjEiko25pDiuVH5YLEa" +``` + ### omni_sendrawtx Broadcasts a raw Omni Layer transaction. @@ -302,7 +319,7 @@ Broadcasts a raw Omni Layer transaction. 1. ***fromaddress (string, required):*** the address to send from 2. ***rawtransaction (string, required):*** the hex-encoded raw transaction 3. ***referenceaddress (string, optional):*** a reference address (empty by default) -4. ***redeemaddress (string, optional):*** an address that can spent the transaction dust (sender by default) +4. ***redeemaddress (string, optional):*** an address that can spend the transaction dust (sender by default) 5. ***referenceamount (string, optional):*** a bitcoin amount that is sent to the receiver (minimal by default) **Example:** diff --git a/src/omnicore/rpctx.cpp b/src/omnicore/rpctx.cpp index 6d3c60c1027c..6e5a18f75574 100644 --- a/src/omnicore/rpctx.cpp +++ b/src/omnicore/rpctx.cpp @@ -48,7 +48,7 @@ Value omni_send(const Array& params, bool fHelp) "2. toaddress (string, required) the address of the receiver\n" "3. propertyid (number, required) the identifier of the tokens to send\n" "4. amount (string, required) the amount to send\n" - "5. redeemaddress (string, optional) an address that can spent the transaction dust (sender by default)\n" + "5. redeemaddress (string, optional) an address that can spend the transaction dust (sender by default)\n" "6. referenceamount (string, optional) a bitcoin amount that is sent to the receiver (minimal by default)\n" "\nResult:\n" @@ -105,7 +105,7 @@ Value omni_sendall(const Array& params, bool fHelp) "\nArguments:\n" "1. fromaddress (string, required) the address to send from\n" "2. toaddress (string, required) the address of the receiver\n" - "3. redeemaddress (string, optional) an address that can spent the transaction dust (sender by default)\n" + "3. redeemaddress (string, optional) an address that can spend the transaction dust (sender by default)\n" "4. referenceamount (string, optional) a bitcoin amount that is sent to the receiver (minimal by default)\n" "\nResult:\n" @@ -533,7 +533,7 @@ Value omni_sendsto(const Array& params, bool fHelp) "1. fromaddress (string, required) the address to send from\n" "2. propertyid (number, required) the identifier of the tokens to distribute\n" "3. amount (string, required) the amount to distribute\n" - "4. redeemaddress (string, optional) an address that can spent the transaction dust (sender by default)\n" + "4. redeemaddress (string, optional) an address that can spend the transaction dust (sender by default)\n" "\nResult:\n" "\"hash\" (string) the hex-encoded transaction hash\n" From b4d9508845beba9a73fcba34155431899ff98397 Mon Sep 17 00:00:00 2001 From: dexX7 Date: Fri, 31 Jul 2015 17:31:22 +0200 Subject: [PATCH 10/12] Slightly refine handling of "send all" transactions --- src/omnicore/omnicore.cpp | 52 +++++++++++++++++++++--------------- src/omnicore/omnicore.h | 7 +++-- src/omnicore/rpctxobject.cpp | 2 +- src/omnicore/tx.cpp | 16 +++++------ 4 files changed, 44 insertions(+), 33 deletions(-) diff --git a/src/omnicore/omnicore.cpp b/src/omnicore/omnicore.cpp index a40ae4e3dc58..187ea5f147d0 100644 --- a/src/omnicore/omnicore.cpp +++ b/src/omnicore/omnicore.cpp @@ -3111,18 +3111,23 @@ int CMPTxList::getNumberOfMetaDExCancels(const uint256 txid) return numberOfCancels; } -int CMPTxList::getNumberOfSubRecords(const uint256 txid) +/** + * Returns the number of sub records. + */ +int CMPTxList::getNumberOfSubRecords(const uint256& txid) { - if (!pdb) return 0; int numberOfSubRecords = 0; - std::vector vstr; - string strValue; + + std::string strValue; Status status = pdb->Get(readoptions, txid.ToString(), &strValue); if (status.ok()) { - // parse the string returned & obtain the number of sub records - boost::split(vstr, strValue, boost::is_any_of(":"), token_compress_on); - if (4 <= vstr.size()) numberOfSubRecords = atoi(vstr[3]); + std::vector vstr; + boost::split(vstr, strValue, boost::is_any_of(":"), boost::token_compress_on); + if (4 <= vstr.size()) { + numberOfSubRecords = boost::lexical_cast(vstr[3]); + } } + return numberOfSubRecords; } @@ -3172,17 +3177,20 @@ string CMPTxList::getKeyValue(string key) if (status.ok()) { return strValue; } else { return ""; } } -bool CMPTxList::getSendAllDetails(const uint256& txid, int subSend, uint32_t *propertyId, int64_t *amount) +/** + * Retrieves details about a "send all" record. + */ +bool CMPTxList::getSendAllDetails(const uint256& txid, int subSend, uint32_t& propertyId, int64_t& amount) { - if (!pdb) return 0; - std::vector vstr; - string strValue; - Status status = pdb->Get(readoptions, txid.ToString()+"-"+to_string(subSend), &strValue); + std::string strKey = strprintf("%s-%d", txid.ToString(), subSend); + std::string strValue; + leveldb::Status status = pdb->Get(readoptions, strKey, &strValue); if (status.ok()) { - boost::split(vstr, strValue, boost::is_any_of(":"), token_compress_on); + std::vector vstr; + boost::split(vstr, strValue, boost::is_any_of(":"), boost::token_compress_on); if (2 == vstr.size()) { - *propertyId = atoi(vstr[0]); - *amount = boost::lexical_cast(vstr[1]);; + propertyId = boost::lexical_cast(vstr[0]); + amount = boost::lexical_cast(vstr[1]); return true; } } @@ -3265,15 +3273,17 @@ void CMPTxList::recordMetaDExCancelTX(const uint256 &txidMaster, const uint256 & } } +/** + * Records a "send all" sub record. + */ void CMPTxList::recordSendAllSubRecord(const uint256& txid, int subRecordNumber, uint32_t propertyId, int64_t nValue) { - if (!pdb) return; - - const std::string& key = strprintf("%s-%d", txid.ToString(), subRecordNumber); - const std::string& value = strprintf("%d:%d", propertyId, nValue); + std::string strKey = strprintf("%s-%d", txid.ToString(), subRecordNumber); + std::string strValue = strprintf("%d:%d", propertyId, nValue); - Status status = pdb->Put(writeoptions, key, value); - if (msc_debug_txdb) PrintToLog("%s(): Key:%s, Value:%s, Status:%s\n", __FUNCTION__, key, value, status.ToString()); + leveldb::Status status = pdb->Put(writeoptions, strKey, strValue); + ++nWritten; + if (msc_debug_txdb) PrintToLog("%s(): store: %s=%s, status: %s\n", __func__, strKey, strValue, status.ToString()); } void CMPTxList::recordPaymentTX(const uint256 &txid, bool fValid, int nBlock, unsigned int vout, unsigned int propertyId, uint64_t nValue, string buyer, string seller) diff --git a/src/omnicore/omnicore.h b/src/omnicore/omnicore.h index 3b91753073dd..834f2182946b 100644 --- a/src/omnicore/omnicore.h +++ b/src/omnicore/omnicore.h @@ -224,14 +224,17 @@ class CMPTxList : public CDBBase void recordTX(const uint256 &txid, bool fValid, int nBlock, unsigned int type, uint64_t nValue); void recordPaymentTX(const uint256 &txid, bool fValid, int nBlock, unsigned int vout, unsigned int propertyId, uint64_t nValue, string buyer, string seller); void recordMetaDExCancelTX(const uint256 &txidMaster, const uint256 &txidSub, bool fValid, int nBlock, unsigned int propertyId, uint64_t nValue); + /** Records a "send all" sub record. */ void recordSendAllSubRecord(const uint256& txid, int subRecordNumber, uint32_t propertyId, int64_t nvalue); string getKeyValue(string key); uint256 findMetaDExCancel(const uint256 txid); - int getNumberOfSubRecords(const uint256 txid); + /** Returns the number of sub records. */ + int getNumberOfSubRecords(const uint256& txid); int getNumberOfMetaDExCancels(const uint256 txid); bool getPurchaseDetails(const uint256 txid, int purchaseNumber, string *buyer, string *seller, uint64_t *vout, uint64_t *propertyId, uint64_t *nValue); - bool getSendAllDetails(const uint256& txid, int subSend, uint32_t *propertyId, int64_t *amount); + /** Retrieves details about a "send all" record. */ + bool getSendAllDetails(const uint256& txid, int subSend, uint32_t& propertyId, int64_t& amount); int getMPTransactionCountTotal(); int getMPTransactionCountBlock(int block); diff --git a/src/omnicore/rpctxobject.cpp b/src/omnicore/rpctxobject.cpp index 59c0ef066ef1..fee45706a65b 100644 --- a/src/omnicore/rpctxobject.cpp +++ b/src/omnicore/rpctxobject.cpp @@ -549,7 +549,7 @@ int populateRPCSendAllSubSends(const uint256& txid, Array& subSends) int64_t amount; { LOCK(cs_tally); - p_txlistdb->getSendAllDetails(txid, subSend, &propertyId, &amount); + p_txlistdb->getSendAllDetails(txid, subSend, propertyId, amount); } subSendObj.push_back(Pair("propertyid", (uint64_t)propertyId)); subSendObj.push_back(Pair("divisible", isPropertyDivisible(propertyId))); diff --git a/src/omnicore/tx.cpp b/src/omnicore/tx.cpp index c0166c6b7f89..575e7a6cffe5 100644 --- a/src/omnicore/tx.cpp +++ b/src/omnicore/tx.cpp @@ -993,22 +993,20 @@ int CMPTransaction::logicMath_SendAll() return (PKT_ERROR_SEND_ALL -54); } - bool fSent = false; uint32_t propertyId = ptally->init(); int numberOfPropertiesSent = 0; while (0 != (propertyId = ptally->next())) { - int64_t money = ptally->getMoney(propertyId, BALANCE); - if (money > 0) { - fSent = true; - numberOfPropertiesSent++; - assert(update_tally_map(sender, propertyId, -money, BALANCE)); - assert(update_tally_map(receiver, propertyId, money, BALANCE)); - p_txlistdb->recordSendAllSubRecord(txid, numberOfPropertiesSent, propertyId, money); + int64_t moneyAvailable = ptally->getMoney(propertyId, BALANCE); + if (moneyAvailable > 0) { + ++numberOfPropertiesSent; + assert(update_tally_map(sender, propertyId, -moneyAvailable, BALANCE)); + assert(update_tally_map(receiver, propertyId, moneyAvailable, BALANCE)); + p_txlistdb->recordSendAllSubRecord(txid, numberOfPropertiesSent, propertyId, moneyAvailable); } } - if (!fSent) { + if (!numberOfPropertiesSent) { PrintToLog("%s(): rejected: sender %s has no tokens to send\n", __func__, sender); return (PKT_ERROR_SEND_ALL -55); } From 539cf51c4bde8da330d6a932a1b8d649ccbc8f30 Mon Sep 17 00:00:00 2001 From: dexX7 Date: Tue, 4 Aug 2015 14:09:08 +0200 Subject: [PATCH 11/12] Support ecosystem parameter for "send all" transactions The new transaction format is: [version: 0] [type: 4] [ecosystem] --- src/omnicore/createpayload.cpp | 7 ++++--- src/omnicore/createpayload.h | 2 +- src/omnicore/doc/rpc-api.md | 9 +++++---- src/omnicore/rpctx.cpp | 22 ++++++++++++---------- src/omnicore/rpctxobject.cpp | 2 ++ src/omnicore/rules.cpp | 2 +- src/omnicore/test/create_payload_tests.cpp | 5 +++-- src/omnicore/tx.cpp | 21 ++++++++++++++++++--- src/omnicore/tx.h | 2 +- src/rpcclient.cpp | 1 + 10 files changed, 48 insertions(+), 25 deletions(-) diff --git a/src/omnicore/createpayload.cpp b/src/omnicore/createpayload.cpp index 8b3fbe59875f..ff52b4fe3813 100644 --- a/src/omnicore/createpayload.cpp +++ b/src/omnicore/createpayload.cpp @@ -43,16 +43,17 @@ std::vector CreatePayload_SimpleSend(uint32_t propertyId, uint64_ return payload; } -std::vector CreatePayload_SendAll() +std::vector CreatePayload_SendAll(uint8_t ecosystem) { std::vector payload; - uint16_t messageType = 4; uint16_t messageVer = 0; - mastercore::swapByteOrder16(messageType); + uint16_t messageType = 4; mastercore::swapByteOrder16(messageVer); + mastercore::swapByteOrder16(messageType); PUSH_BACK_BYTES(payload, messageVer); PUSH_BACK_BYTES(payload, messageType); + PUSH_BACK_BYTES(payload, ecosystem); return payload; } diff --git a/src/omnicore/createpayload.h b/src/omnicore/createpayload.h index a5b9fb8d7e6b..01e0720a692f 100644 --- a/src/omnicore/createpayload.h +++ b/src/omnicore/createpayload.h @@ -6,7 +6,7 @@ #include std::vector CreatePayload_SimpleSend(uint32_t propertyId, uint64_t amount); -std::vector CreatePayload_SendAll(); +std::vector CreatePayload_SendAll(uint8_t ecosystem); std::vector CreatePayload_DExSell(uint32_t propertyId, uint64_t amountForSale, uint64_t amountDesired, uint8_t timeLimit, uint64_t minFee, uint8_t subAction); std::vector CreatePayload_DExAccept(uint32_t propertyId, uint64_t amount); std::vector CreatePayload_SendToOwners(uint32_t propertyId, uint64_t amount); diff --git a/src/omnicore/doc/rpc-api.md b/src/omnicore/doc/rpc-api.md index 49591f40ca24..2071cd6e7745 100644 --- a/src/omnicore/doc/rpc-api.md +++ b/src/omnicore/doc/rpc-api.md @@ -295,19 +295,20 @@ $ omnicore-cli "omni_sendchangeissuer" "1ARjWDkZ7kT9fwjPrjcQyvbXDkEySzKHwu" "3HT ### omni_sendall -Transfers *all* tokens owned to the recipient. +Transfers all available tokens in the given ecosystem to the recipient. **Arguments:** 1. ***fromaddress (string, required):*** the address to send from 2. ***toaddress (string, required):*** the address of the receiver -3. ***redeemaddress (string, optional):*** an address that can spend the transaction dust (sender by default) -4. ***referenceamount (string, optional):*** a bitcoin amount that is sent to the receiver (minimal by default) +3. ***ecosystem (number, required):*** the ecosystem of the tokens to send: (1) main, (2) test +4. ***redeemaddress (string, optional):*** an address that can spend the transaction dust (sender by default) +5. ***referenceamount (string, optional):*** a bitcoin amount that is sent to the receiver (minimal by default) **Example:** ```bash -$ omnicore-cli "omni_sendall" "3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY" "37FaKponF7zqoMLUjEiko25pDiuVH5YLEa" +$ omnicore-cli "omni_sendall" "3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY" "37FaKponF7zqoMLUjEiko25pDiuVH5YLEa" 2 ``` ### omni_sendrawtx diff --git a/src/omnicore/rpctx.cpp b/src/omnicore/rpctx.cpp index 6e5a18f75574..3835ada8da75 100644 --- a/src/omnicore/rpctx.cpp +++ b/src/omnicore/rpctx.cpp @@ -96,37 +96,39 @@ Value omni_send(const Array& params, bool fHelp) // omni_sendall - send all Value omni_sendall(const Array& params, bool fHelp) { - if (fHelp || params.size() < 2 || params.size() > 4) + if (fHelp || params.size() < 3 || params.size() > 5) throw runtime_error( - "omni_sendall \"fromaddress\" \"toaddress\" ( \"redeemaddress\" \"referenceamount\" )\n" + "omni_sendall \"fromaddress\" \"toaddress\" ecosystem ( \"redeemaddress\" \"referenceamount\" )\n" - "\nTransfers *all* tokens owned to the recipient.\n" + "\nTransfers all available tokens in the given ecosystem to the recipient.\n" "\nArguments:\n" "1. fromaddress (string, required) the address to send from\n" "2. toaddress (string, required) the address of the receiver\n" - "3. redeemaddress (string, optional) an address that can spend the transaction dust (sender by default)\n" - "4. referenceamount (string, optional) a bitcoin amount that is sent to the receiver (minimal by default)\n" + "3. ecosystem (number, required) the ecosystem of the tokens to send: (1) main, (2) test\n" + "4. redeemaddress (string, optional) an address that can spend the transaction dust (sender by default)\n" + "5. referenceamount (string, optional) a bitcoin amount that is sent to the receiver (minimal by default)\n" "\nResult:\n" "\"hash\" (string) the hex-encoded transaction hash\n" "\nExamples:\n" - + HelpExampleCli("omni_sendall", "\"3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY\" \"37FaKponF7zqoMLUjEiko25pDiuVH5YLEa\"") - + HelpExampleRpc("omni_sendall", "\"3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY\", \"37FaKponF7zqoMLUjEiko25pDiuVH5YLEa\"") + + HelpExampleCli("omni_sendall", "\"3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY\" \"37FaKponF7zqoMLUjEiko25pDiuVH5YLEa\" 2") + + HelpExampleRpc("omni_sendall", "\"3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY\", \"37FaKponF7zqoMLUjEiko25pDiuVH5YLEa\" 2") ); // obtain parameters & info std::string fromAddress = ParseAddress(params[0]); std::string toAddress = ParseAddress(params[1]); - std::string redeemAddress = (params.size() > 2 && !ParseText(params[2]).empty()) ? ParseAddress(params[2]): ""; - int64_t referenceAmount = (params.size() > 3) ? ParseAmount(params[3], true): 0; + uint8_t ecosystem = ParseEcosystem(params[2]); + std::string redeemAddress = (params.size() > 3 && !ParseText(params[3]).empty()) ? ParseAddress(params[3]): ""; + int64_t referenceAmount = (params.size() > 4) ? ParseAmount(params[4], true): 0; // perform checks RequireSaneReferenceAmount(referenceAmount); // create a payload for the transaction - std::vector payload = CreatePayload_SendAll(); + std::vector payload = CreatePayload_SendAll(ecosystem); // request the wallet build the transaction (and if needed commit it) uint256 txid; diff --git a/src/omnicore/rpctxobject.cpp b/src/omnicore/rpctxobject.cpp index fee45706a65b..3e3890db6229 100644 --- a/src/omnicore/rpctxobject.cpp +++ b/src/omnicore/rpctxobject.cpp @@ -250,6 +250,8 @@ void populateRPCTypeSendToOwners(CMPTransaction& omniObj, Object& txobj, bool ex void populateRPCTypeSendAll(CMPTransaction& omniObj, Object& txobj) { Array subSends; + if (omniObj.getEcosystem() == 1) txobj.push_back(Pair("ecosystem", "main")); + if (omniObj.getEcosystem() == 2) txobj.push_back(Pair("ecosystem", "test")); if (populateRPCSendAllSubSends(omniObj.getHash(), subSends) > 0) txobj.push_back(Pair("subsends", subSends)); } diff --git a/src/omnicore/rules.cpp b/src/omnicore/rules.cpp index c2e74b1385af..805a51fc026a 100644 --- a/src/omnicore/rules.cpp +++ b/src/omnicore/rules.cpp @@ -57,7 +57,7 @@ std::vector CConsensusParams::GetRestrictions() const { MSC_TYPE_METADEX_CANCEL_PAIR, MP_TX_PKT_V0, false, MSC_METADEX_BLOCK }, { MSC_TYPE_METADEX_CANCEL_ECOSYSTEM, MP_TX_PKT_V0, true, MSC_METADEX_BLOCK }, - { MSC_TYPE_SEND_ALL, MP_TX_PKT_V0, true, MSC_SEND_ALL_BLOCK }, + { MSC_TYPE_SEND_ALL, MP_TX_PKT_V0, false, MSC_SEND_ALL_BLOCK }, { MSC_TYPE_OFFER_ACCEPT_A_BET, MP_TX_PKT_V0, false, MSC_BET_BLOCK }, }; diff --git a/src/omnicore/test/create_payload_tests.cpp b/src/omnicore/test/create_payload_tests.cpp index 8939e9a89931..d8eded810baa 100644 --- a/src/omnicore/test/create_payload_tests.cpp +++ b/src/omnicore/test/create_payload_tests.cpp @@ -33,9 +33,10 @@ BOOST_AUTO_TEST_CASE(payload_send_to_owners) BOOST_AUTO_TEST_CASE(payload_send_all) { // Send to owners [type 4, version 0] - std::vector vch = CreatePayload_SendAll(); + std::vector vch = CreatePayload_SendAll( + static_cast(2)); // ecosystem: Test - BOOST_CHECK_EQUAL(HexStr(vch), "00000004"); + BOOST_CHECK_EQUAL(HexStr(vch), "0000000402"); } BOOST_AUTO_TEST_CASE(payload_dex_offer) diff --git a/src/omnicore/tx.cpp b/src/omnicore/tx.cpp index 575e7a6cffe5..ec05a299a0e6 100644 --- a/src/omnicore/tx.cpp +++ b/src/omnicore/tx.cpp @@ -224,9 +224,16 @@ bool CMPTransaction::interpret_SendToOwners() /** Tx 4 */ bool CMPTransaction::interpret_SendAll() { - if (pkt_size < 4) { + if (pkt_size < 5) { return false; } + memcpy(&ecosystem, &pkt[4], 1); + + property = ecosystem; // provide a hint for the UI, TODO: better handling! + + if ((!rpcOnly && msc_debug_packets) || msc_debug_packets_readonly) { + PrintToLog("\t ecosystem: %d\n", (int)ecosystem); + } return true; } @@ -970,12 +977,12 @@ int CMPTransaction::logicMath_SendToOwners() /** Tx 4 */ int CMPTransaction::logicMath_SendAll() { - if (!IsTransactionTypeAllowed(block, property, type, version)) { + if (!IsTransactionTypeAllowed(block, ecosystem, type, version)) { PrintToLog("%s(): rejected: type %d or version %d not permitted for property %d at block %d\n", __func__, type, version, - property, + ecosystem, block); return (PKT_ERROR_SEND_ALL -22); } @@ -997,6 +1004,14 @@ int CMPTransaction::logicMath_SendAll() int numberOfPropertiesSent = 0; while (0 != (propertyId = ptally->next())) { + // only transfer tokens in the specified ecosystem + if (ecosystem == OMNI_PROPERTY_MSC && isTestEcosystemProperty(propertyId)) { + continue; + } + if (ecosystem == OMNI_PROPERTY_TMSC && isMainEcosystemProperty(propertyId)) { + continue; + } + int64_t moneyAvailable = ptally->getMoney(propertyId, BALANCE); if (moneyAvailable > 0) { ++numberOfPropertiesSent; diff --git a/src/omnicore/tx.h b/src/omnicore/tx.h index 8a068dddb894..2530d39976e0 100644 --- a/src/omnicore/tx.h +++ b/src/omnicore/tx.h @@ -54,7 +54,7 @@ class CMPTransaction // CreatePropertyMananged, GrantTokens, RevokeTokens, ChangeIssuer unsigned int property; - // CreatePropertyFixed, CreatePropertyVariable, CreatePropertyMananged, MetaDEx + // CreatePropertyFixed, CreatePropertyVariable, CreatePropertyMananged, MetaDEx, SendAll unsigned char ecosystem; // CreatePropertyFixed, CreatePropertyVariable, CreatePropertyMananged diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index f763dfa0aa14..43fd18f15614 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -133,6 +133,7 @@ static const CRPCConvertParam vRPCConvertParams[] = /* Omni Core - transaction calls */ { "omni_send", 2 }, { "omni_sendsto", 1 }, + { "omni_sendall", 2 }, { "omni_sendtrade", 1 }, { "omni_sendtrade", 3 }, { "omni_sendcanceltradesbyprice", 1 }, From 5d05e9ff8808c9548ce7c72d102bd0d4b1a434cb Mon Sep 17 00:00:00 2001 From: dexX7 Date: Tue, 1 Sep 2015 02:20:26 +0200 Subject: [PATCH 12/12] Use "N/A" amount label for "send all" in UI (zathras-crypto) --- src/qt/overviewpage.cpp | 8 ++++++-- src/qt/txhistorydialog.cpp | 9 +++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 93a3bb2c4ee7..a5c43af83367 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -127,7 +127,9 @@ class TxViewDelegate : public QAbstractItemDelegate omniAmountStr = QString::fromStdString(FormatIndivisibleMP(p_pending->amount) + getTokenLabel(p_pending->prop)); } // override amount for cancels - if (p_pending->type == MSC_TYPE_METADEX_CANCEL_PRICE || p_pending->type == MSC_TYPE_METADEX_CANCEL_PAIR || p_pending->type == MSC_TYPE_METADEX_CANCEL_ECOSYSTEM) { + if (p_pending->type == MSC_TYPE_METADEX_CANCEL_PRICE || p_pending->type == MSC_TYPE_METADEX_CANCEL_PAIR || + p_pending->type == MSC_TYPE_METADEX_CANCEL_ECOSYSTEM || p_pending->type == MSC_TYPE_SEND_ALL || + p_pending->type == 0 /* Unknown */) { omniAmountStr = QString::fromStdString("N/A"); } } @@ -203,7 +205,9 @@ class TxViewDelegate : public QAbstractItemDelegate } // override amount for cancels - if (mp_obj.getType() == MSC_TYPE_METADEX_CANCEL_PRICE || mp_obj.getType() == MSC_TYPE_METADEX_CANCEL_PAIR || mp_obj.getType() == MSC_TYPE_METADEX_CANCEL_ECOSYSTEM) { + if (mp_obj.getType() == MSC_TYPE_METADEX_CANCEL_PRICE || mp_obj.getType() == MSC_TYPE_METADEX_CANCEL_PAIR || + mp_obj.getType() == MSC_TYPE_METADEX_CANCEL_ECOSYSTEM || mp_obj.getType() == MSC_TYPE_SEND_ALL || + mp_obj.getType() == 0 /* Unknown */) { omniAmountStr = QString::fromStdString("N/A"); } diff --git a/src/qt/txhistorydialog.cpp b/src/qt/txhistorydialog.cpp index 2b967400a3d9..d98701aef8a5 100644 --- a/src/qt/txhistorydialog.cpp +++ b/src/qt/txhistorydialog.cpp @@ -239,7 +239,11 @@ int TXHistoryDialog::PopulateHistoryMap() htxo.amount = "-" + FormatShortMP(pending.prop, pending.amount) + getTokenLabel(pending.prop); bool fundsMoved = true; htxo.txType = shrinkTxType(pending.type, &fundsMoved); - if (pending.type == MSC_TYPE_METADEX_CANCEL_PRICE || pending.type == MSC_TYPE_METADEX_CANCEL_PAIR || pending.type == MSC_TYPE_METADEX_CANCEL_ECOSYSTEM) htxo.amount = "N/A"; + if (pending.type == MSC_TYPE_METADEX_CANCEL_PRICE || pending.type == MSC_TYPE_METADEX_CANCEL_PAIR || + pending.type == MSC_TYPE_METADEX_CANCEL_ECOSYSTEM || pending.type == MSC_TYPE_SEND_ALL || + pending.type == 0 /* Unknown */) { + htxo.amount = "N/A"; + } txHistoryMap.insert(std::make_pair(txHash, htxo)); nProcessed++; continue; @@ -320,7 +324,8 @@ int TXHistoryDialog::PopulateHistoryMap() } } // override - hide display amount for cancels and unknown transactions as we can't display amount/property as no prop exists - if (type == MSC_TYPE_METADEX_CANCEL_PRICE || type == MSC_TYPE_METADEX_CANCEL_PAIR || type == MSC_TYPE_METADEX_CANCEL_ECOSYSTEM || htxo.txType == "Unknown") { + if (type == MSC_TYPE_METADEX_CANCEL_PRICE || type == MSC_TYPE_METADEX_CANCEL_PAIR || + type == MSC_TYPE_METADEX_CANCEL_ECOSYSTEM || type == MSC_TYPE_SEND_ALL || htxo.txType == "Unknown") { displayAmount = "N/A"; } // override - display amount received not STO amount in packet (the total amount) for STOs I didn't send