From 59996fefba43a07d46ca861552df97fffdbee967 Mon Sep 17 00:00:00 2001 From: Zathras Date: Fri, 17 Nov 2017 14:14:58 +1100 Subject: [PATCH 1/5] Update OmniTXDB to also store the processing result --- src/omnicore/omnicore.cpp | 37 ++++++++++++++++++++++++++++--------- src/omnicore/omnicore.h | 3 ++- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/omnicore/omnicore.cpp b/src/omnicore/omnicore.cpp index 3217ddcf84c3f..de25fdee427b8 100644 --- a/src/omnicore/omnicore.cpp +++ b/src/omnicore/omnicore.cpp @@ -2344,7 +2344,7 @@ bool mastercore_handler_tx(const CTransaction& tx, int nBlock, unsigned int idx, if (interp_ret != PKT_ERROR - 2) { bool bValid = (0 <= interp_ret); p_txlistdb->recordTX(tx.GetHash(), bValid, nBlock, mp_obj.getType(), mp_obj.getNewAmount()); - p_OmniTXDB->RecordTransaction(tx.GetHash(), idx); + p_OmniTXDB->RecordTransaction(tx.GetHash(), idx, interp_ret); } fFoundTx |= (interp_ret == 0); } @@ -2456,28 +2456,47 @@ int mastercore::WalletTxBuilder(const std::string& senderAddress, const std::str } -void COmniTransactionDB::RecordTransaction(const uint256& txid, uint32_t posInBlock) +void COmniTransactionDB::RecordTransaction(const uint256& txid, uint32_t posInBlock, int processingResult) { assert(pdb); const std::string key = txid.ToString(); - const std::string value = strprintf("%d", posInBlock); + const std::string value = strprintf("%d:%d", posInBlock, processingResult); Status status = pdb->Put(writeoptions, key, value); ++nWritten; } -uint32_t COmniTransactionDB::FetchTransactionPosition(const uint256& txid) +std::vector COmniTransactionDB::FetchTransactionDetails(const uint256& txid) { assert(pdb); - - const std::string key = txid.ToString(); std::string strValue; - uint32_t posInBlock = 999999; // setting an initial arbitrarily high value will ensure transaction is always "last" in event of bug/exploit + std::vector vTransactionDetails; - Status status = pdb->Get(readoptions, key, &strValue); + Status status = pdb->Get(readoptions, txid.ToString(), &strValue); if (status.ok()) { - posInBlock = boost::lexical_cast(strValue); + std::vector vStr; + boost::split(vStr, strValue, boost::is_any_of(":"), boost::token_compress_on); + if (vStr.size() == 2) { + vTransactionDetails.push_back(vStr[0]); + vTransactionDetails.push_back(vStr[1]); + } else { + PrintToLog("ERROR: Entry (%s) found in OmniTXDB with unexpected number of attributes!\n", txid.GetHex()); + } + } else { + PrintToLog("ERROR: Entry (%s) could not be loaded from OmniTXDB!\n", txid.GetHex()); + } + + return vTransactionDetails; +} + +uint32_t COmniTransactionDB::FetchTransactionPosition(const uint256& txid) +{ + uint32_t posInBlock = 999999; // setting an initial arbitrarily high value will ensure transaction is always "last" in event of bug/exploit + + std::vector vTransactionDetails = FetchTransactionDetails(txid); + if (vTransactionDetails.size() == 2) { + posInBlock = boost::lexical_cast(vTransactionDetails[0]); } return posInBlock; diff --git a/src/omnicore/omnicore.h b/src/omnicore/omnicore.h index 29b9019ec1fba..bad943caafc8b 100644 --- a/src/omnicore/omnicore.h +++ b/src/omnicore/omnicore.h @@ -177,7 +177,8 @@ class COmniTransactionDB : public CDBBase * * and so on... */ - void RecordTransaction(const uint256& txid, uint32_t posInBlock); + void RecordTransaction(const uint256& txid, uint32_t posInBlock, int processingResult); + std::vector FetchTransactionDetails(const uint256& txid); uint32_t FetchTransactionPosition(const uint256& txid); }; From d1ec20527f29f2527b2622acbf0f80fad5aba0bd Mon Sep 17 00:00:00 2001 From: Zathras Date: Fri, 17 Nov 2017 14:17:37 +1100 Subject: [PATCH 2/5] Add FetchInvalidReason() to OmniTXDB --- src/omnicore/omnicore.cpp | 12 ++++++++++++ src/omnicore/omnicore.h | 1 + 2 files changed, 13 insertions(+) diff --git a/src/omnicore/omnicore.cpp b/src/omnicore/omnicore.cpp index de25fdee427b8..00fe460e3c49c 100644 --- a/src/omnicore/omnicore.cpp +++ b/src/omnicore/omnicore.cpp @@ -2502,6 +2502,18 @@ uint32_t COmniTransactionDB::FetchTransactionPosition(const uint256& txid) return posInBlock; } +std::string COmniTransactionDB::FetchInvalidReason(const uint256& txid) +{ + int processingResult = -999999; + + std::vector vTransactionDetails = FetchTransactionDetails(txid); + if (vTransactionDetails.size() == 2) { + processingResult = boost::lexical_cast(vTransactionDetails[1]); + } + + return error_str(processingResult); +} + std::set CMPTxList::GetSeedBlocks(int startHeight, int endHeight) { std::set setSeedBlocks; diff --git a/src/omnicore/omnicore.h b/src/omnicore/omnicore.h index bad943caafc8b..1296c2774a1b6 100644 --- a/src/omnicore/omnicore.h +++ b/src/omnicore/omnicore.h @@ -180,6 +180,7 @@ class COmniTransactionDB : public CDBBase void RecordTransaction(const uint256& txid, uint32_t posInBlock, int processingResult); std::vector FetchTransactionDetails(const uint256& txid); uint32_t FetchTransactionPosition(const uint256& txid); + std::string FetchInvalidReason(const uint256& txid); }; /** LevelDB based storage for STO recipients. From 86514d187e8358cce72c0991fee34c8f7aada92a Mon Sep 17 00:00:00 2001 From: Zathras Date: Fri, 17 Nov 2017 14:24:36 +1100 Subject: [PATCH 3/5] Port parsing errors to errors.h --- src/omnicore/errors.h | 246 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 246 insertions(+) diff --git a/src/omnicore/errors.h b/src/omnicore/errors.h index 9b0100652b96e..5f085bb6c92d8 100644 --- a/src/omnicore/errors.h +++ b/src/omnicore/errors.h @@ -3,6 +3,8 @@ #include +#include "omnicore/omnicore.h" + enum MPRPCErrorCode { //INTERNAL_1packet @@ -76,6 +78,250 @@ inline std::string error_str(int ec) { case MP_ERR_COMMIT_TX: ec_str = "Error committing transaction"; break; + + case PKT_ERROR -1: + ec_str = "Attempt to execute logic in RPC mode"; + break; + case PKT_ERROR -2: + ec_str = "Failed to interpret transaction"; + break; + case PKT_ERROR -22: + ec_str = "Transaction type or version not permitted"; + break; + case PKT_ERROR -51: + ec_str = "Sender is not authorized"; + break; + case PKT_ERROR -54: + ec_str = "Activation failed"; + break; + + case PKT_ERROR -100: + ec_str = "Transaction is not a supported type"; + break; + case PKT_ERROR -500: + ec_str = "Transaction version is not supported"; + break; + case PKT_ERROR -999: + ec_str = "Failed to determine subaction"; + break; + + case PKT_ERROR_SEND -22: + ec_str = "Transaction type or version not permitted"; + break; + case PKT_ERROR_SEND -23: + ec_str = "Value out of range or zero"; + break; + case PKT_ERROR_SEND -24: + ec_str = "Property does not exist"; + break; + case PKT_ERROR_SEND -25: + ec_str = "Sender has insufficient balance"; + break; + + case PKT_ERROR_STO -22: + ec_str = "Transaction type or version not permitted"; + break; + case PKT_ERROR_STO -23: + ec_str = "Value out of range or zero"; + break; + case PKT_ERROR_STO -24: + ec_str = "Property does not exist"; + break; + case PKT_ERROR_STO -25: + ec_str = "Sender has insufficient balance"; + break; + case PKT_ERROR_STO -26: + ec_str = "No other owners of the property"; + break; + case PKT_ERROR_STO -27: + ec_str = "Sender has insufficient balance to pay for fee"; + break; + case PKT_ERROR_STO -28: + ec_str = "Sender has insufficient balance to pay for amount + fee"; + break; + + case PKT_ERROR_SEND_ALL -22: + ec_str = "Transaction type or version not permitted"; + break; + case PKT_ERROR_SEND_ALL -54: + ec_str = "Sender has no tokens to send"; + break; + case PKT_ERROR_SEND_ALL -55: + ec_str = "Sender has no tokens to send"; + break; + + case PKT_ERROR_TRADEOFFER -22: + ec_str = "Transaction type or version not permitted"; + break; + case PKT_ERROR_TRADEOFFER -23: + ec_str = "Value out of range or zero"; + break; + case PKT_ERROR_TRADEOFFER -47: + ec_str = "Property for sale must be OMNI or TOMNI"; + break; + case PKT_ERROR_TRADEOFFER -49: + ec_str = "Sender has no active sell offer for the property"; + break; + case PKT_ERROR_TRADEOFFER -48: + ec_str = "Sender already has an active sell offer for the property"; + break; + + case DEX_ERROR_SELLOFFER -101: + ec_str = "Value out of range or zero"; + break; + case DEX_ERROR_SELLOFFER -10: + ec_str = "Sender already has an active sell offer for the property"; + break; + case DEX_ERROR_SELLOFFER -25: + ec_str = "Sender has insufficient balance"; + break; + case DEX_ERROR_SELLOFFER -11: + ec_str = "Sender has no active sell offer for the property"; + break; + case DEX_ERROR_SELLOFFER -12: + ec_str = "Sender has no active sell offer for the property"; + break; + + case DEX_ERROR_ACCEPT -15: + ec_str = "No matching sell offer for accept order found"; + break; + case DEX_ERROR_ACCEPT -20: + ec_str = "Cannot locate accept to destroy"; + break; + case DEX_ERROR_ACCEPT -22: + ec_str = "Transaction type or version not permitted"; + break; + case DEX_ERROR_ACCEPT -23: + ec_str = "Value out of range or zero"; + break; + case DEX_ERROR_ACCEPT -205: + ec_str = "An accept from the sender to the recipient already exists"; + break; + case DEX_ERROR_ACCEPT -105: + ec_str = "Transaction fee too small"; + break; + + case PKT_ERROR_METADEX -21: + ec_str = "Ecosystem is invalid"; + break; + case PKT_ERROR_METADEX -22: + ec_str = "Transaction type or version not permitted"; + break; + case PKT_ERROR_METADEX -25: + ec_str = "Sender has insufficient balance"; + break; + case PKT_ERROR_METADEX -29: + ec_str = "Property for sale and desired property are not be equal"; + break; + case PKT_ERROR_METADEX -30: + ec_str = "Property for sale and desired property are not in the same ecosystem"; + break; + case PKT_ERROR_METADEX -31: + ec_str = "Property for sale does not exist"; + break; + case PKT_ERROR_METADEX -32: + ec_str = "Property desired does not exist"; + break; + case PKT_ERROR_METADEX -33: + ec_str = "Amount for sale out of range or zero"; + break; + case PKT_ERROR_METADEX -34: + ec_str = "Amount desired out of range or zero"; + break; + case PKT_ERROR_METADEX -35: + ec_str = "One side of the trade must be OMNI or TOMNI"; + break; + + case METADEX_ERROR -1: + ec_str = "Unknown MetaDEx (Add) error"; + break; + case METADEX_ERROR -20: + ec_str = "Unknown MetaDEx (Cancel Price) error"; + break; + case METADEX_ERROR -30: + ec_str = "Unknown MetaDEx (Cancel Pair) error"; + break; + case METADEX_ERROR -40: + ec_str = "Unknown MetaDEx (Cancel Everything) error"; + break; + case METADEX_ERROR -66: + ec_str = "Trade has a unit price of zero"; + break; + case METADEX_ERROR -70: + ec_str = "Trade already exists"; + break; + + case PKT_ERROR_SP -20: + ec_str = "Block is not in the active chain"; + break; + case PKT_ERROR_SP -21: + ec_str = "Ecosystem is invalid"; + break; + case PKT_ERROR_SP -22: + ec_str = "Transaction type or version not permitted"; + break; + case PKT_ERROR_SP -23: + ec_str = "Value out of range or zero"; + break; + case PKT_ERROR_SP -24: + ec_str = "Desired property does not exist"; + break; + case PKT_ERROR_SP -36: + ec_str = "Invalid property type"; + break; + case PKT_ERROR_SP -37: + ec_str = "Property name is empty"; + break; + case PKT_ERROR_SP -38: + ec_str = "Deadline is in the past"; + break; + case PKT_ERROR_SP -39: + ec_str = "Sender has an active crowdsale"; + break; + case PKT_ERROR_SP -40: + ec_str = "Sender has no active crowdsale"; + break; + case PKT_ERROR_SP -41: + ec_str = "Property identifier mismatch"; + break; + case PKT_ERROR_SP -42: + ec_str = "Property is not managed"; + break; + case PKT_ERROR_SP -43: + ec_str = "Sender is not the issuer of the property"; + break; + case PKT_ERROR_SP -44: + ec_str = "Attempt to grant more than the maximum number of tokens"; + break; + case PKT_ERROR_SP -50: + ec_str = "Tokens to issue and desired property are not in the same ecosystem"; + break; + + case PKT_ERROR_TOKENS -22: + ec_str = "Transaction type or version not permitted"; + break; + case PKT_ERROR_TOKENS -23: + ec_str = "Value out of range or zero"; + break; + case PKT_ERROR_TOKENS -24: + ec_str = "Property does not exist"; + break; + case PKT_ERROR_TOKENS -25: + ec_str = "Sender has insufficient balance"; + break; + case PKT_ERROR_TOKENS -39: + ec_str = "Sender has an active crowdsale"; + break; + case PKT_ERROR_TOKENS -43: + ec_str = "Sender is not the issuer of the property"; + break; + case PKT_ERROR_TOKENS -45: + ec_str = "Receiver is empty"; + break; + case PKT_ERROR_TOKENS -46: + ec_str = "Receiver has an active crowdsale"; + break; + default: ec_str = "Unknown error"; } From abdbbd7e8ec0e8e36950831198ef4f98a3a43bea Mon Sep 17 00:00:00 2001 From: Zathras Date: Fri, 17 Nov 2017 14:26:42 +1100 Subject: [PATCH 4/5] Add 'invalidreason' attribute to RPC response for omni_gettransaction --- src/omnicore/rpc.cpp | 1 + src/omnicore/rpctxobject.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/omnicore/rpc.cpp b/src/omnicore/rpc.cpp index f00a447bb6cdc..7501e2e935162 100644 --- a/src/omnicore/rpc.cpp +++ b/src/omnicore/rpc.cpp @@ -1674,6 +1674,7 @@ UniValue omni_gettransaction(const UniValue& params, bool fHelp) " \"fee\" : \"n.nnnnnnnn\", (string) the transaction fee in bitcoins\n" " \"blocktime\" : nnnnnnnnnn, (number) the timestamp of the block that contains the transaction\n" " \"valid\" : true|false, (boolean) whether the transaction is valid\n" + " \"invalidreason\" : \"reason\", (string) if a transaction is invalid, the reason \n" " \"version\" : n, (number) the transaction version\n" " \"type_int\" : n, (number) the transaction type as number\n" " \"type\" : \"type\", (string) the transaction type as string\n" diff --git a/src/omnicore/rpctxobject.cpp b/src/omnicore/rpctxobject.cpp index 01b374a573307..d373fad61215d 100644 --- a/src/omnicore/rpctxobject.cpp +++ b/src/omnicore/rpctxobject.cpp @@ -143,6 +143,9 @@ int populateRPCTransactionObject(const CTransaction& tx, const uint256& blockHas // state and chain related information if (confirmations != 0 && !blockHash.IsNull()) { txobj.push_back(Pair("valid", valid)); + if (!valid) { + txobj.push_back(Pair("invalidreason", p_OmniTXDB->FetchInvalidReason(txid))); + } txobj.push_back(Pair("blockhash", blockHash.GetHex())); txobj.push_back(Pair("blocktime", blockTime)); txobj.push_back(Pair("positioninblock", positionInBlock)); From df6181965b10432c404a55be03650e98ae04c9fe Mon Sep 17 00:00:00 2001 From: Zathras Date: Fri, 17 Nov 2017 14:27:33 +1100 Subject: [PATCH 5/5] Increment DB_VERSION to force a reparse (to add invalid reasons to levelDB) --- src/omnicore/omnicore.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/omnicore/omnicore.h b/src/omnicore/omnicore.h index 1296c2774a1b6..e4020d8e61b1d 100644 --- a/src/omnicore/omnicore.h +++ b/src/omnicore/omnicore.h @@ -36,7 +36,7 @@ int const MAX_STATE_HISTORY = 50; #define TEST_ECO_PROPERTY_1 (0x80000003UL) // increment this value to force a refresh of the state (similar to --startclean) -#define DB_VERSION 3 +#define DB_VERSION 5 // could probably also use: int64_t maxInt64 = std::numeric_limits::max(); // maximum numeric values from the spec: