From 0b76fa31b1835979ef539722fd59c7ec2f514d57 Mon Sep 17 00:00:00 2001 From: Zathras Date: Mon, 27 Feb 2017 18:23:07 +1100 Subject: [PATCH 1/7] Core functions for atomic metadata --- src/omnicore/metadata.cpp | 111 ++++++++++++++++++++++++++++++++++++++ src/omnicore/metadata.h | 42 +++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 src/omnicore/metadata.cpp create mode 100644 src/omnicore/metadata.h diff --git a/src/omnicore/metadata.cpp b/src/omnicore/metadata.cpp new file mode 100644 index 0000000000000..b1557429da4d4 --- /dev/null +++ b/src/omnicore/metadata.cpp @@ -0,0 +1,111 @@ +/** + * @file metadata.cpp + * + * This file contains code for handling atomic metadata. + * + * TODO: Required - add a DeleteAboveBlock() function to remove entries from metadata DB during reorg + */ + +#include "omnicore/metadata.h" + +#include "omnicore/omnicore.h" +#include "omnicore/log.h" + +#include "leveldb/db.h" +#include "arith_uint256.h" +#include "uint256.h" + +#include + +#include + +#include + +using namespace mastercore; + +// Gets a metadata ID from a string (first and last bytes of the sha256 hash of the string) +std::string GetMetadataID(std::string metadata) +{ + uint256 hash; + SHA256_CTX shaCtx; + SHA256_Init(&shaCtx); + SHA256_Update(&shaCtx, metadata.c_str(), metadata.length()); + SHA256_Final((unsigned char*)&hash, &shaCtx); + + std::string metadataId = ""; + std::string hashStr = hash.GetHex(); + if (hashStr.length() == 64) { + metadataId = hashStr.substr(0,2) + hashStr.substr(62,2); + } + + return metadataId; +} + +// Adds metadata to the DB +void COmniMetadataDB::AddMetadata(int block, std::string address, std::string metadata) +{ + std::string key = strprintf("%s:%s", address, GetMetadataID(metadata)); + std::string value = strprintf("%d:%s", block, metadata); + + leveldb::Status status = pdb->Put(writeoptions, key, value); + assert(status.ok()); + + return; +} + +// Obtains the metadata for a given metadata id +std::string COmniMetadataDB::GetMetadata(std::string address, std::string metadataId) +{ + assert(pdb); + + std::string key = strprintf("%s:%s", address, metadataId); + std::string value = ""; + std::string metadata = ""; + + leveldb::Status status = pdb->Get(readoptions, key, &value); + if (status.ok()) { + std::vector vstr; + boost::split(vstr, value, boost::is_any_of(":"), boost::token_compress_on); + assert(2 == vstr.size()); + metadata = vstr[1]; + } + + return metadata; +} + +// Obtains all the metadata published by a given address +std::set COmniMetadataDB::GetAddressMetadata(std::string address) +{ + assert(pdb); + + std::set metadataIds; + leveldb::Iterator* it = NewIterator(); + + for(it->SeekToFirst(); it->Valid(); it->Next()) { + std::vector vstr; + std::string key = it->key().ToString(); + boost::split(vstr, key, boost::is_any_of(":"), boost::token_compress_on); + assert(2 == vstr.size()); + std::string entryAddress = vstr[0]; + if (entryAddress == address) { + metadataIds.insert(vstr[1]); + } + } + + delete it; + + return metadataIds; +} + +void COmniMetadataDB::printAll() +{ + int count = 0; + leveldb::Iterator* it = NewIterator(); + + for(it->SeekToFirst(); it->Valid(); it->Next()) { + ++count; + PrintToConsole("entry #%8d= %s:%s\n", count, it->key().ToString(), it->value().ToString()); + } + + delete it; +} diff --git a/src/omnicore/metadata.h b/src/omnicore/metadata.h new file mode 100644 index 0000000000000..19b03ecfd7534 --- /dev/null +++ b/src/omnicore/metadata.h @@ -0,0 +1,42 @@ +#ifndef OMNICORE_METADATA_H +#define OMNICORE_METADATA_H + +#include "leveldb/db.h" + +#include "omnicore/log.h" +#include "omnicore/persistence.h" + +#include +#include +#include + +std::string GetMetadataID(std::string metadata); + +/** LevelDB based storage for atomic metadata. */ +class COmniMetadataDB : public CDBBase +{ +public: + COmniMetadataDB(const boost::filesystem::path& path, bool fWipe) + { + leveldb::Status status = Open(path, fWipe); + PrintToConsole("Loading metadata database: %s\n", status.ToString()); + } + + virtual ~COmniMetadataDB() + { + if (msc_debug_persistence) PrintToLog("COmniMetadataDB closed\n"); + } + + void AddMetadata(int block, std::string address, std::string metadata); + std::string GetMetadata(std::string address, std::string metadataId); + std::set GetAddressMetadata(std::string address); + + void printAll(); +}; + +namespace mastercore +{ + extern COmniMetadataDB *p_OmniMetadataDB; +} + +#endif // OMNICORE_METADATA_H From 144eeadde4599535df073610aa82ff1078fdba49 Mon Sep 17 00:00:00 2001 From: Zathras Date: Mon, 27 Feb 2017 18:23:48 +1100 Subject: [PATCH 2/7] Update makefile for new metadata.cpp/h --- src/Makefile.omnicore.include | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Makefile.omnicore.include b/src/Makefile.omnicore.include index 50def9071305d..758919f74455d 100644 --- a/src/Makefile.omnicore.include +++ b/src/Makefile.omnicore.include @@ -12,6 +12,7 @@ OMNICORE_H = \ omnicore/log.h \ omnicore/mbstring.h \ omnicore/mdex.h \ + omnicore/metadata.h \ omnicore/notifications.h \ omnicore/omnicore.h \ omnicore/parse_string.h \ @@ -51,6 +52,7 @@ OMNICORE_CPP = \ omnicore/log.cpp \ omnicore/mbstring.cpp \ omnicore/mdex.cpp \ + omnicore/metadata.cpp \ omnicore/notifications.cpp \ omnicore/omnicore.cpp \ omnicore/parse_string.cpp \ From b5570e46196d63962c08fedb9600a021101ddcab Mon Sep 17 00:00:00 2001 From: Zathras Date: Mon, 27 Feb 2017 18:24:50 +1100 Subject: [PATCH 3/7] Add metadata DB handlers --- src/omnicore/omnicore.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/omnicore/omnicore.cpp b/src/omnicore/omnicore.cpp index 9c571c3a9ac2a..44adf36678c20 100644 --- a/src/omnicore/omnicore.cpp +++ b/src/omnicore/omnicore.cpp @@ -15,6 +15,7 @@ #include "omnicore/fees.h" #include "omnicore/log.h" #include "omnicore/mdex.h" +#include "omnicore/metadata.h" #include "omnicore/notifications.h" #include "omnicore/pending.h" #include "omnicore/persistence.h" @@ -133,6 +134,7 @@ CMPSTOList *mastercore::s_stolistdb; COmniTransactionDB *mastercore::p_OmniTXDB; COmniFeeCache *mastercore::p_feecache; COmniFeeHistory *mastercore::p_feehistory; +COmniMetadataDB *mastercore::p_OmniMetadataDB; // indicate whether persistence is enabled at this point, or not // used to write/read files, for breakout mode, debugging, etc. @@ -2087,6 +2089,7 @@ void clear_all_state() p_OmniTXDB->Clear(); p_feecache->Clear(); p_feehistory->Clear(); + p_OmniMetadataDB->Clear(); assert(p_txlistdb->setDBVersion() == DB_VERSION); // new set of databases, set DB version exodus_prev = 0; } @@ -2138,6 +2141,7 @@ int mastercore_init() boost::filesystem::path omniTXDBPath = GetDataDir() / "Omni_TXDB"; boost::filesystem::path feesPath = GetDataDir() / "OMNI_feecache"; boost::filesystem::path feeHistoryPath = GetDataDir() / "OMNI_feehistory"; + boost::filesystem::path omniMetadataDBPath = GetDataDir() / "OMNI_metadata"; if (boost::filesystem::exists(persistPath)) boost::filesystem::remove_all(persistPath); if (boost::filesystem::exists(txlistPath)) boost::filesystem::remove_all(txlistPath); if (boost::filesystem::exists(tradePath)) boost::filesystem::remove_all(tradePath); @@ -2146,6 +2150,7 @@ int mastercore_init() if (boost::filesystem::exists(omniTXDBPath)) boost::filesystem::remove_all(omniTXDBPath); if (boost::filesystem::exists(feesPath)) boost::filesystem::remove_all(feesPath); if (boost::filesystem::exists(feeHistoryPath)) boost::filesystem::remove_all(feeHistoryPath); + if (boost::filesystem::exists(omniMetadataDBPath)) boost::filesystem::remove_all(omniMetadataDBPath); PrintToLog("Success clearing persistence files in datadir %s\n", GetDataDir().string()); startClean = true; } catch (const boost::filesystem::filesystem_error& e) { @@ -2161,6 +2166,7 @@ int mastercore_init() p_OmniTXDB = new COmniTransactionDB(GetDataDir() / "Omni_TXDB", fReindex); p_feecache = new COmniFeeCache(GetDataDir() / "OMNI_feecache", fReindex); p_feehistory = new COmniFeeHistory(GetDataDir() / "OMNI_feehistory", fReindex); + p_OmniMetadataDB = new COmniMetadataDB(GetDataDir() / "OMNI_metadata", fReindex); MPPersistencePath = GetDataDir() / "MP_persist"; TryCreateDirectory(MPPersistencePath); @@ -2270,6 +2276,10 @@ int mastercore_shutdown() delete p_feehistory; p_feehistory = NULL; } + if (p_OmniMetadataDB) { + delete p_OmniMetadataDB; + p_OmniMetadataDB = NULL; + } mastercoreInitialized = 0; From 17bb33c206bc5e4ec2f79c7f01434839fdb62df7 Mon Sep 17 00:00:00 2001 From: Zathras Date: Mon, 27 Feb 2017 18:26:53 +1100 Subject: [PATCH 4/7] Add feature 13 to wrap atomic metadata with an activation --- src/omnicore/rules.cpp | 15 +++++++++++++++ src/omnicore/rules.h | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/src/omnicore/rules.cpp b/src/omnicore/rules.cpp index 3355b964572d6..49942ce171386 100644 --- a/src/omnicore/rules.cpp +++ b/src/omnicore/rules.cpp @@ -67,6 +67,8 @@ std::vector CConsensusParams::GetRestrictions() const { MSC_TYPE_SEND_ALL, MP_TX_PKT_V0, false, MSC_SEND_ALL_BLOCK }, + { MSC_TYPE_PUBLISH_METADATA, MP_TX_PKT_V0, true, MSC_METADATA_BLOCK }, + { MSC_TYPE_OFFER_ACCEPT_A_BET, MP_TX_PKT_V0, false, MSC_BET_BLOCK }, }; @@ -169,6 +171,7 @@ CMainConsensusParams::CMainConsensusParams() MSC_STO_BLOCK = 342650; MSC_METADEX_BLOCK = 999999; MSC_SEND_ALL_BLOCK = 999999; + MSC_METADATA_BLOCK = 999999; MSC_BET_BLOCK = 999999; MSC_STOV1_BLOCK = 999999; // Other feature activations: @@ -207,6 +210,7 @@ CTestNetConsensusParams::CTestNetConsensusParams() MSC_STO_BLOCK = 0; MSC_METADEX_BLOCK = 0; MSC_SEND_ALL_BLOCK = 0; + MSC_METADATA_BLOCK = 0; MSC_BET_BLOCK = 999999; MSC_STOV1_BLOCK = 0; // Other feature activations: @@ -245,6 +249,7 @@ CRegTestConsensusParams::CRegTestConsensusParams() MSC_STO_BLOCK = 0; MSC_METADEX_BLOCK = 0; MSC_SEND_ALL_BLOCK = 0; + MSC_METADATA_BLOCK = 0; MSC_BET_BLOCK = 999999; MSC_STOV1_BLOCK = 999999; // Other feature activations: @@ -415,6 +420,9 @@ bool ActivateFeature(uint16_t featureId, int activationBlock, uint32_t minClient case FEATURE_STOV1: MutableConsensusParams().MSC_STOV1_BLOCK = activationBlock; break; + case FEATURE_METADATA: + MutableConsensusParams().MSC_METADATA_BLOCK = activationBlock; + break; default: supported = false; break; @@ -483,6 +491,9 @@ bool DeactivateFeature(uint16_t featureId, int transactionBlock) case FEATURE_STOV1: MutableConsensusParams().MSC_STOV1_BLOCK = 999999; break; + case FEATURE_METADATA: + MutableConsensusParams().MSC_METADATA_BLOCK = 999999; + break; default: return false; break; @@ -513,6 +524,7 @@ std::string GetFeatureName(uint16_t featureId) case FEATURE_TRADEALLPAIRS: return "Allow trading all pairs on the Distributed Exchange"; case FEATURE_FEES: return "Fee system (inc 0.05% fee from trades of non-Omni pairs)"; case FEATURE_STOV1: return "Cross-property Send To Owners"; + case FEATURE_METADATA: return "Atomic Metadata"; default: return "Unknown feature"; } @@ -557,6 +569,9 @@ bool IsFeatureActivated(uint16_t featureId, int transactionBlock) case FEATURE_STOV1: activationBlock = params.MSC_STOV1_BLOCK; break; + case FEATURE_METADATA: + activationBlock = params.MSC_METADATA_BLOCK; + break; default: return false; } diff --git a/src/omnicore/rules.h b/src/omnicore/rules.h index a974dd40cab3b..b56f1b5ae19d1 100644 --- a/src/omnicore/rules.h +++ b/src/omnicore/rules.h @@ -34,6 +34,8 @@ const uint16_t FEATURE_TRADEALLPAIRS = 8; const uint16_t FEATURE_FEES = 9; //! Feature identifier to enable cross property (v1) Send To Owners const uint16_t FEATURE_STOV1 = 10; +//! Feature identifier to enable atomic metadata +const uint16_t FEATURE_METADATA = 13; //! When (propertyTotalTokens / OMNI_FEE_THRESHOLD) is reached fee distribution will occur const int64_t OMNI_FEE_THRESHOLD = 100000; // 0.001% @@ -115,6 +117,8 @@ class CConsensusParams int MSC_BET_BLOCK; //! Block to enable cross property STO (v1) int MSC_STOV1_BLOCK; + //! Block to enable atomic metadata + int MSC_METADATA_BLOCK; //! Block to deactivate crowdsale participations when "granting tokens" int GRANTEFFECTS_FEATURE_BLOCK; From 6a1912f83b8bf23465b74d062ae6098a06ef67ca Mon Sep 17 00:00:00 2001 From: Zathras Date: Mon, 27 Feb 2017 18:27:57 +1100 Subject: [PATCH 5/7] Add payload creation support for atomic metadata --- src/omnicore/createpayload.cpp | 17 +++++++++++++++++ src/omnicore/createpayload.h | 1 + 2 files changed, 18 insertions(+) diff --git a/src/omnicore/createpayload.cpp b/src/omnicore/createpayload.cpp index b4847f31acdc4..11cd0f20eed0a 100644 --- a/src/omnicore/createpayload.cpp +++ b/src/omnicore/createpayload.cpp @@ -401,6 +401,23 @@ std::vector CreatePayload_MetaDExCancelEcosystem(uint8_t ecosyste return payload; } +std::vector CreatePayload_PublishMetadata(std::string metadata) +{ + std::vector payload; + uint16_t messageType = 80; + uint16_t messageVer = 0; + + mastercore::swapByteOrder16(messageVer); + mastercore::swapByteOrder16(messageType); + + PUSH_BACK_BYTES(payload, messageVer); + PUSH_BACK_BYTES(payload, messageType); + payload.insert(payload.end(), metadata.begin(), metadata.end()); + payload.push_back('\0'); + + return payload; +} + std::vector CreatePayload_DeactivateFeature(uint16_t featureId) { std::vector payload; diff --git a/src/omnicore/createpayload.h b/src/omnicore/createpayload.h index 4392383575fa8..96c293f5553a2 100644 --- a/src/omnicore/createpayload.h +++ b/src/omnicore/createpayload.h @@ -25,6 +25,7 @@ std::vector CreatePayload_MetaDExTrade(uint32_t propertyIdForSale std::vector CreatePayload_MetaDExCancelPrice(uint32_t propertyIdForSale, uint64_t amountForSale, uint32_t propertyIdDesired, uint64_t amountDesired); std::vector CreatePayload_MetaDExCancelPair(uint32_t propertyIdForSale, uint32_t propertyIdDesired); std::vector CreatePayload_MetaDExCancelEcosystem(uint8_t ecosystem); +std::vector CreatePayload_PublishMetadata(const std::string metadata); std::vector CreatePayload_OmniCoreAlert(uint16_t alertType, uint32_t expiryValue, const std::string& alertMessage); std::vector CreatePayload_DeactivateFeature(uint16_t featureId); std::vector CreatePayload_ActivateFeature(uint16_t featureId, uint32_t activationBlock, uint32_t minClientVersion); From f8612c6d33a5860ed99665289725e7c7d562bcee Mon Sep 17 00:00:00 2001 From: Zathras Date: Mon, 27 Feb 2017 18:28:53 +1100 Subject: [PATCH 6/7] Add transaction decoding support for tx80 --- src/omnicore/omnicore.h | 1 + src/omnicore/tx.cpp | 44 +++++++++++++++++++++++++++++++++++++++++ src/omnicore/tx.h | 7 +++++++ 3 files changed, 52 insertions(+) diff --git a/src/omnicore/omnicore.h b/src/omnicore/omnicore.h index 2ab04820c9efd..f1b530db8e508 100644 --- a/src/omnicore/omnicore.h +++ b/src/omnicore/omnicore.h @@ -86,6 +86,7 @@ enum TransactionType { MSC_TYPE_GRANT_PROPERTY_TOKENS = 55, MSC_TYPE_REVOKE_PROPERTY_TOKENS = 56, MSC_TYPE_CHANGE_ISSUER_ADDRESS = 70, + MSC_TYPE_PUBLISH_METADATA = 80, OMNICORE_MESSAGE_TYPE_DEACTIVATION = 65533, OMNICORE_MESSAGE_TYPE_ACTIVATION = 65534, OMNICORE_MESSAGE_TYPE_ALERT = 65535 diff --git a/src/omnicore/tx.cpp b/src/omnicore/tx.cpp index a76d3b6cc3eb2..ed7153570c944 100644 --- a/src/omnicore/tx.cpp +++ b/src/omnicore/tx.cpp @@ -8,6 +8,7 @@ #include "omnicore/fees.h" #include "omnicore/log.h" #include "omnicore/mdex.h" +#include "omnicore/metadata.h" #include "omnicore/notifications.h" #include "omnicore/omnicore.h" #include "omnicore/rules.h" @@ -59,6 +60,7 @@ std::string mastercore::strTransactionType(uint16_t txType) case MSC_TYPE_GRANT_PROPERTY_TOKENS: return "Grant Property Tokens"; case MSC_TYPE_REVOKE_PROPERTY_TOKENS: return "Revoke Property Tokens"; case MSC_TYPE_CHANGE_ISSUER_ADDRESS: return "Change Issuer Address"; + case MSC_TYPE_PUBLISH_METADATA: return "Publish Metadata"; case MSC_TYPE_NOTIFICATION: return "Notification"; case OMNICORE_MESSAGE_TYPE_ALERT: return "ALERT"; case OMNICORE_MESSAGE_TYPE_DEACTIVATION: return "Feature Deactivation"; @@ -149,6 +151,9 @@ bool CMPTransaction::interpret_Transaction() case MSC_TYPE_CHANGE_ISSUER_ADDRESS: return interpret_ChangeIssuer(); + case MSC_TYPE_PUBLISH_METADATA: + return interpret_PublishMetadata(); + case OMNICORE_MESSAGE_TYPE_DEACTIVATION: return interpret_Deactivation(); @@ -631,6 +636,24 @@ bool CMPTransaction::interpret_ChangeIssuer() return true; } +/** Tx 80 */ +bool CMPTransaction::interpret_PublishMetadata() +{ + if (pkt_size < 5) { + return false; + } + + const char* p = 4 + (char*) &pkt; + std::string metadataStr(p); + memcpy(metadata, metadataStr.c_str(), std::min(metadataStr.length(), sizeof(metadata)-1)); + + if ((!rpcOnly && msc_debug_packets) || msc_debug_packets_readonly) { + PrintToLog("\t metadata: %d\n", metadata); + } + + return true; +} + /** Tx 65533 */ bool CMPTransaction::interpret_Deactivation() { @@ -769,6 +792,9 @@ int CMPTransaction::interpretPacket() case MSC_TYPE_CHANGE_ISSUER_ADDRESS: return logicMath_ChangeIssuer(); + case MSC_TYPE_PUBLISH_METADATA: + return logicMath_PublishMetadata(); + case OMNICORE_MESSAGE_TYPE_DEACTIVATION: return logicMath_Deactivation(); @@ -1947,6 +1973,24 @@ int CMPTransaction::logicMath_ChangeIssuer() return 0; } +/** Tx 80 */ +int CMPTransaction::logicMath_PublishMetadata() +{ + 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 -22); + } + + p_OmniMetadataDB->AddMetadata(block, sender, metadata); + + return 0; +} + /** Tx 65533 */ int CMPTransaction::logicMath_Deactivation() { diff --git a/src/omnicore/tx.h b/src/omnicore/tx.h index 6a09806219c55..890462d36d1da 100644 --- a/src/omnicore/tx.h +++ b/src/omnicore/tx.h @@ -57,6 +57,9 @@ class CMPTransaction // SendToOwners v1 unsigned int distribution_property; + // Publish Metadata + char metadata[SP_STRING_FIELD_LEN]; + // CreatePropertyFixed, CreatePropertyVariable, CreatePropertyMananged, MetaDEx, SendAll unsigned char ecosystem; @@ -119,6 +122,7 @@ class CMPTransaction bool interpret_GrantTokens(); bool interpret_RevokeTokens(); bool interpret_ChangeIssuer(); + bool interpret_PublishMetadata(); bool interpret_Activation(); bool interpret_Deactivation(); bool interpret_Alert(); @@ -142,6 +146,7 @@ class CMPTransaction int logicMath_GrantTokens(); int logicMath_RevokeTokens(); int logicMath_ChangeIssuer(); + int logicMath_PublishMetadata(); int logicMath_Activation(); int logicMath_Deactivation(); int logicMath_Alert(); @@ -202,6 +207,7 @@ class CMPTransaction uint32_t getMinClientVersion() const { return min_client_version; } unsigned int getIndexInBlock() const { return tx_idx; } uint32_t getDistributionProperty() const { return distribution_property; } + std::string getMetadata() const { return metadata; } /** Creates a new CMPTransaction object. */ CMPTransaction() @@ -253,6 +259,7 @@ class CMPTransaction activation_block = 0; min_client_version = 0; distribution_property = 0; + memset(&metadata, 0, sizeof(metadata)); } /** Sets the given values. */ From cf37f4cf3cfecd70de5ae41f2b057c21848b220a Mon Sep 17 00:00:00 2001 From: Zathras Date: Mon, 27 Feb 2017 18:29:46 +1100 Subject: [PATCH 7/7] Add RPC support to expose metadata functions --- src/omnicore/rpc.cpp | 121 +++++++++++++++++++++++++++++++++++ src/omnicore/rpctx.cpp | 45 +++++++++++++ src/omnicore/rpctx.h | 1 + src/omnicore/rpctxobject.cpp | 12 ++++ src/omnicore/rpctxobject.h | 1 + 5 files changed, 180 insertions(+) diff --git a/src/omnicore/rpc.cpp b/src/omnicore/rpc.cpp index 0a1a97d400566..eb458447df3e6 100644 --- a/src/omnicore/rpc.cpp +++ b/src/omnicore/rpc.cpp @@ -15,6 +15,7 @@ #include "omnicore/fetchwallettx.h" #include "omnicore/log.h" #include "omnicore/mdex.h" +#include "omnicore/metadata.h" #include "omnicore/notifications.h" #include "omnicore/omnicore.h" #include "omnicore/rpcrequirements.h" @@ -149,6 +150,118 @@ bool BalanceToJSON(const std::string& address, uint32_t property, UniValue& bala } } +// Gets the metadata ID from a string +UniValue omni_getmetadataid(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "omni_getmetadataid metadatastring\n" + "\nGet the metadata id for a provided string.\n" + "\nArguments:\n" + "1. metadatastring (string, required) the metadata string\n" + "\nResult:\n" + "{\n" + " \"metadataid\" : \"metadataid\", (string) the metadata id\n" + " \"metadata\" : \"metadata\", (string) the metadata string\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("omni_getmetadataid", "TEST") + + HelpExampleRpc("omni_getmetadataid", "TEST") + ); + + std::string metadata = params[0].get_str(); + std::string metadataId = GetMetadataID(metadata); + + UniValue response(UniValue::VOBJ); + + response.push_back(Pair("metadataid", metadataId)); + response.push_back(Pair("metadata", metadata)); + + return response; +} + +// Gets the metadata for an address and ID +UniValue omni_getmetadata(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 2) + throw runtime_error( + "omni_getmetadata address metadataid\n" + "\nGets the metadata associated with an address and id.\n" + "\nArguments:\n" + "1. address (string, required) the address that published the metadatag\n" + "2. metadataid (string, required) the metadata id\n" + "\nResult:\n" + "{\n" + " \"address\" : \"address\", (string) the publishing address\n" + " \"metadataid\" : \"metadataid\", (string) the metadata id\n" + " \"metadata\" : \"metadata\", (string) the metadata string\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("omni_getmetadata", "\"1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P\" \"abcd\"") + + HelpExampleRpc("omni_getmetadata", "\"1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P\", \"abcd\"") + ); + + std::string address = ParseAddress(params[0]); + std::string metadataId = params[1].get_str(); + + if (metadataId.length() != 4) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Metadata identifers are 4 characters long"); + } + + UniValue response(UniValue::VOBJ); + + std::string metadata = p_OmniMetadataDB->GetMetadata(address, metadataId); + + response.push_back(Pair("address", address)); + response.push_back(Pair("metadataid", metadataId)); + response.push_back(Pair("metadata", metadata)); + + return response; +} + +// Gets all the metadata for an address +UniValue omni_getaddressmetadata(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "omni_getaddressmetadata address\n" + "\nGets all the metadata associated with an address.\n" + "\nArguments:\n" + "1. address (string, required) the address that published the metadata\n" + "\nResult:\n" + "{\n" + " \"address\" : \"address\", (string) the address\n" + " \"addressmetadata\": [ (array of JSON objects) a list of metadata objects\n" + " {\n" + " \"metadataid\" : \"metadataid\", (string) the metadata id\n" + " \"metadata\" : \"metadata\", (string) the metadata string\n" + " },\n" + " ...\n" + " ]\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("omni_getaddressmetadata", "\"1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P\"") + + HelpExampleRpc("omni_getaddressmetadata", "\"1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P\"") + ); + + std::string address = ParseAddress(params[0]); + + UniValue response(UniValue::VOBJ); + UniValue addressMetadata(UniValue::VARR); + + response.push_back(Pair("address", address)); + std::set metadataIds = p_OmniMetadataDB->GetAddressMetadata(address); + for (std::set::iterator it = metadataIds.begin(); it != metadataIds.end(); it++) { + UniValue metadataObj(UniValue::VOBJ); + std::string metadata = p_OmniMetadataDB->GetMetadata(address, *it); + metadataObj.push_back(Pair("metadataid", GetMetadataID(metadata))); + metadataObj.push_back(Pair("metadata", metadata)); + addressMetadata.push_back(metadataObj); + } + response.push_back(Pair("addressmetadata", addressMetadata)); + return response; +} + // Obtains details of a fee distribution UniValue omni_getfeedistribution(const UniValue& params, bool fHelp) { @@ -734,6 +847,11 @@ UniValue mscrpc(const UniValue& params, bool fHelp) break; } + case 15: + { + p_OmniMetadataDB->printAll(); + break; + } default: break; } @@ -2187,6 +2305,9 @@ static const CRPCCommand commands[] = { "omni layer (data retrieval)", "omni_getfeetrigger", &omni_getfeetrigger, false }, { "omni layer (data retrieval)", "omni_getfeedistribution", &omni_getfeedistribution, false }, { "omni layer (data retrieval)", "omni_getfeedistributions", &omni_getfeedistributions, false }, + { "omni layer (data retrieval)", "omni_getmetadataid", &omni_getmetadataid, true }, + { "omni layer (data retrieval)", "omni_getmetadata", &omni_getmetadata, false }, + { "omni layer (data retrieval)", "omni_getaddressmetadata", &omni_getaddressmetadata, false }, #ifdef ENABLE_WALLET { "omni layer (data retrieval)", "omni_listtransactions", &omni_listtransactions, false }, { "omni layer (data retrieval)", "omni_getfeeshare", &omni_getfeeshare, false }, diff --git a/src/omnicore/rpctx.cpp b/src/omnicore/rpctx.cpp index 525035ddd78f3..7501ee0244a10 100644 --- a/src/omnicore/rpctx.cpp +++ b/src/omnicore/rpctx.cpp @@ -1099,6 +1099,50 @@ UniValue omni_sendchangeissuer(const UniValue& params, bool fHelp) } } +UniValue omni_sendpublishmetadata(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 2) + throw runtime_error( + "omni_sendpublishmetadata \"fromaddress\" \"metadata\"\n" + + "\nPublish a metadata string.\n" + + "\nArguments:\n" + "1. fromaddress (string, required) the address to publish the metadata from\n" + "2. metadata (string, required) the metadata string to publish\n" + + "\nResult:\n" + "\"hash\" (string) the hex-encoded transaction hash\n" + + "\nExamples:\n" + + HelpExampleCli("omni_sendpublishmetadata", "\"3HTHRxu3aSDV4deakjC7VmsiUp7c6dfbvs\" \"Metadata\"") + + HelpExampleRpc("omni_sendpublishmetadata", "\"3HTHRxu3aSDV4deakjC7VmsiUp7c6dfbvs\", \"Metadata\"") + ); + + // obtain parameters & info + std::string fromAddress = ParseAddress(params[0]); + std::string metadata = params[1].get_str(); + + // create a payload for the transaction + std::vector payload = CreatePayload_PublishMetadata(metadata); + + // request the wallet build the transaction (and if needed commit it) + uint256 txid; + std::string rawHex; + int result = WalletTxBuilder(fromAddress, "", "", 0, 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 { + return txid.GetHex(); + } + } +} + UniValue omni_sendactivation(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 4) @@ -1259,6 +1303,7 @@ static const CRPCCommand commands[] = { "omni layer (transaction creation)", "omni_sendclosecrowdsale", &omni_sendclosecrowdsale, false }, { "omni layer (transaction creation)", "omni_sendchangeissuer", &omni_sendchangeissuer, false }, { "omni layer (transaction creation)", "omni_sendall", &omni_sendall, false }, + { "omni layer (transaction creation)", "omni_sendpublishmetadata", &omni_sendpublishmetadata, false }, { "hidden", "omni_senddeactivation", &omni_senddeactivation, true }, { "hidden", "omni_sendactivation", &omni_sendactivation, false }, { "hidden", "omni_sendalert", &omni_sendalert, true }, diff --git a/src/omnicore/rpctx.h b/src/omnicore/rpctx.h index 07c783ea219c4..18a50b67df46f 100644 --- a/src/omnicore/rpctx.h +++ b/src/omnicore/rpctx.h @@ -21,6 +21,7 @@ UniValue omni_sendcanceltradesbyprice(const UniValue& params, bool fHelp); UniValue omni_sendcanceltradesbypair(const UniValue& params, bool fHelp); UniValue omni_sendcancelalltrades(const UniValue& params, bool fHelp); UniValue omni_sendchangeissuer(const UniValue& params, bool fHelp); +UniValue omni_sendpublishmetadata(const UniValue& params, bool fHelp); UniValue omni_sendactivation(const UniValue& params, bool fHelp); UniValue omni_sendalert(const UniValue& params, bool fHelp); diff --git a/src/omnicore/rpctxobject.cpp b/src/omnicore/rpctxobject.cpp index 01b374a573307..f16b07c0bfeb7 100644 --- a/src/omnicore/rpctxobject.cpp +++ b/src/omnicore/rpctxobject.cpp @@ -9,6 +9,7 @@ #include "omnicore/dex.h" #include "omnicore/errors.h" #include "omnicore/mdex.h" +#include "omnicore/metadata.h" #include "omnicore/omnicore.h" #include "omnicore/pending.h" #include "omnicore/rpctxobject.h" @@ -209,6 +210,9 @@ void populateRPCTypeInfo(CMPTransaction& mp_obj, UniValue& txobj, uint32_t txTyp case MSC_TYPE_CHANGE_ISSUER_ADDRESS: populateRPCTypeChangeIssuer(mp_obj, txobj); break; + case MSC_TYPE_PUBLISH_METADATA: + populateRPCTypePublishMetadata(mp_obj, txobj); + break; case OMNICORE_MESSAGE_TYPE_ACTIVATION: populateRPCTypeActivation(mp_obj, txobj); break; @@ -235,6 +239,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_PUBLISH_METADATA: return false; case MSC_TYPE_SEND_ALL: return true; case OMNICORE_MESSAGE_TYPE_ACTIVATION: return false; } @@ -492,6 +497,13 @@ void populateRPCTypeChangeIssuer(CMPTransaction& omniObj, UniValue& txobj) txobj.push_back(Pair("divisible", isPropertyDivisible(propertyId))); } +void populateRPCTypePublishMetadata(CMPTransaction& omniObj, UniValue& txobj) +{ + std::string metadata = omniObj.getMetadata(); + txobj.push_back(Pair("metadataid", GetMetadataID(metadata))); + txobj.push_back(Pair("metadata", metadata)); +} + void populateRPCTypeActivation(CMPTransaction& omniObj, UniValue& txobj) { txobj.push_back(Pair("featureid", (uint64_t) omniObj.getFeatureId())); diff --git a/src/omnicore/rpctxobject.h b/src/omnicore/rpctxobject.h index e166062c4919c..9391bdadeb2bb 100644 --- a/src/omnicore/rpctxobject.h +++ b/src/omnicore/rpctxobject.h @@ -30,6 +30,7 @@ void populateRPCTypeCloseCrowdsale(CMPTransaction& omniObj, UniValue& txobj); void populateRPCTypeGrant(CMPTransaction& omniObj, UniValue& txobj); void populateRPCTypeRevoke(CMPTransaction& omniOobj, UniValue& txobj); void populateRPCTypeChangeIssuer(CMPTransaction& omniObj, UniValue& txobj); +void populateRPCTypePublishMetadata(CMPTransaction& omniObj, UniValue& txobj); void populateRPCTypeActivation(CMPTransaction& omniObj, UniValue& txobj); void populateRPCExtendedTypeSendToOwners(const uint256 txid, std::string extendedDetailsFilter, UniValue& txobj, uint16_t version);