From c4f5067ac6d800dd88776caec51e083dbc2513e4 Mon Sep 17 00:00:00 2001 From: Bjarki Gunnarsson Date: Fri, 7 Aug 2020 09:28:10 +0000 Subject: [PATCH 01/11] ubi init+gitignore --- .gitignore | 13 ++++++ src/Makefile.am | 2 + src/init.cpp | 1 + src/miner.cpp | 17 ++++++- src/ubi.cpp | 115 ++++++++++++++++++++++++++++++++++++++++++++++++ src/ubi.h | 19 ++++++++ src/util.cpp | 1 + src/util.h | 1 + 8 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 src/ubi.cpp create mode 100644 src/ubi.h diff --git a/.gitignore b/.gitignore index 1637d5bf7..c590ae3f6 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,19 @@ build-aux/ltversion.m4 build-aux/missing build-aux/compile build-aux/test-driver +src/build-aux/config.guess +src/build-aux/config.sub +src/build-aux/depcomp +src/build-aux/install-sh +src/build-aux/ltmain.sh +src/build-aux/libtool.m4 +src/build-aux/lt~obsolete.m4 +src/build-aux/ltoptions.m4 +src/build-aux/ltsugar.m4 +src/build-aux/ltversion.m4 +src/build-aux/missing +src/build-aux/compile +src/build-aux/test-driver config.log config.status configure diff --git a/src/Makefile.am b/src/Makefile.am index b4b94c447..cd865a9f5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -66,6 +66,7 @@ BITCOIN_CORE_H = \ tinyformat.h \ txdb.h \ txmempool.h \ + ubi.h \ ui_interface.h \ uint256.h \ util.h \ @@ -117,6 +118,7 @@ libbitcoin_server_a_SOURCES = \ leveldbwrapper.cpp \ main.cpp \ miner.cpp \ + ubi.cpp \ net.cpp \ noui.cpp \ richlistdb.cpp \ diff --git a/src/init.cpp b/src/init.cpp index a4690f41a..5b41469e4 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -559,6 +559,7 @@ bool AppInit2(boost::thread_group& threadGroup) fServer = GetBoolArg("-server", false); fPrintToConsole = GetBoolArg("-printtoconsole", false); fLogTimestamps = GetBoolArg("-logtimestamps", true); + fUBI = GetBoolArg("-ubi", true); setvbuf(stdout, NULL, _IOLBF, 0); #ifdef ENABLE_WALLET bool fDisableWallet = GetBoolArg("-disablewallet", false); diff --git a/src/miner.cpp b/src/miner.cpp index 3039162b4..a26a819b1 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -10,6 +10,7 @@ #include "main.h" #include "net.h" #include "richlistdb.h" +#include "ubi.h" #ifdef ENABLE_WALLET #include "wallet.h" #endif @@ -366,7 +367,8 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, int algo) LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize); - txNew.vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees); + // miner's reward + txNew.vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees*0.10); //CTxOut minerTxOut = CTxOut(0, scriptPubKeyIn); CScript richpubkey; if(!RichList.NextRichScriptPubKey(richpubkey)) @@ -376,6 +378,19 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, int algo) //txNew.vout.push_back(minerTxOut); txNew.vout.push_back(richTxOut); txNew.vout.push_back(EIASTxOut); + + + if (fUBI && UBI::GetUBIDividends(nFees) > 0) + { + vector ubi_pubkeys = UBI::NextBatch(pindexPrev->nHeight + 1); + for (auto ubi_pubkey : ubi_pubkeys) + { + CTxOut ubi_txout = CTxOut(UBI::GetUBIDividends(nFees), ubi_pubkey); + txNew.vout.push_back(ubi_txout); + } + } + + pblock->vtx[0] = txNew; pblocktemplate->vTxFees[0] = -nFees; diff --git a/src/ubi.cpp b/src/ubi.cpp new file mode 100644 index 000000000..ab3943618 --- /dev/null +++ b/src/ubi.cpp @@ -0,0 +1,115 @@ +#include "ubi.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* To the reader: + * We calculate the next batch of UBI recipients for every thread, + * but we can do it only for each block height when someone has + * actually been paid. + * + * Could move initialization to init.cpp to conform to the other code + * but that's annoying. + */ + +using namespace std; + +// compare recipients only via block-last-paid, the address is irrelevant +bool operator<(const Recipient& lhs, const Recipient& rhs) +{ + return lhs.lastpaid < rhs.lastpaid; +} + +// our list of recipients +vector vRecipients; + +// how many recipient are paid per block +const size_t nBatchSize = 5; + +static boost::once_flag ubiInitFlag = BOOST_ONCE_INIT; + +namespace UBI +{ + +// read ~/.smileycoin/ubi_addresses and put them into vRecipients +// it's alright if there is no file, then it behaves like -ubi=0 +static void InitCirculation() +{ + auto addressfile_path = GetDataDir() / "ubi_addresses"; + + ifstream addressfile(addressfile_path.string()); + + if (!addressfile.good()) + LogPrintf("UBI::InitCirculation() couldn't read ubi_addresses file, not paying any UBI\n"); + + + string ln; + while (getline(addressfile, ln)) + { + // allow empty lines or comments + if (ln[0] == '#' || ln.empty()) + continue; + + // user has not been paid, so he is initialized with the height 0 + vRecipients.push_back({0, CBitcoinAddress(ln)}); + } +} + +// goes through vRecipients and selects the addresses that haven't been paid +// for the longest time. +// in: nHeight, height of the block that pays the addresses +// return: vector of the CScript's that pay the block's ubi recipients +vector NextBatch(const unsigned int nHeight) +{ + boost::call_once(&InitCirculation, ubiInitFlag); + + int stop = min(vRecipients.size(), nBatchSize); + + vector batch(vRecipients.begin(), vRecipients.begin()+stop); + + // choose the recipients with the lowest lastpaid values + for (auto &r : vRecipients) + { + // using our operator< get the iterator of the recipient in batch that + // has been paid most recently + auto it = max_element(batch.begin(), batch.end()); + + if (r < *it) + { + *it = r; + r.lastpaid = nHeight; + } + } + + vector ret; + for (auto r : batch) + { + CScript s; + s.SetDestination(r.address.Get()); + ret.push_back(s); + } + + return ret; +} + +// Similar to GetBlockValueDividends but doesn't depend on block height +// in: nFees, block fees +// return: dividends per recipient, 0 if there are none +int64_t GetUBIDividends(const int64_t nFees) +{ + if (vRecipients.empty()) + return 0; + + int64_t nRecipientCount = min(nBatchSize, vRecipients.size()); + + return (int64_t)(0.9 * nFees) / nRecipientCount; +} + +} // namespace UBI diff --git a/src/ubi.h b/src/ubi.h new file mode 100644 index 000000000..dc7ca5bb0 --- /dev/null +++ b/src/ubi.h @@ -0,0 +1,19 @@ +#include "base58.h" +#include "main.h" + +#include "core.h" +#include "init.h" +#include "txdb.h" + +// height last-paid and receiving address of a ubi recipient +typedef struct { + unsigned int lastpaid; + CBitcoinAddress address; +} Recipient; + +namespace UBI +{ +std::vector NextBatch(const unsigned int nHeight); +int64_t GetUBIDividends(const int64_t nFees); +} + diff --git a/src/util.cpp b/src/util.cpp index 2f762a136..509efcead 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -96,6 +96,7 @@ bool fServer = false; string strMiscWarning; bool fNoListen = false; bool fLogTimestamps = false; +bool fUBI = true; volatile bool fReopenDebugLog = false; CClientUIInterface uiInterface; diff --git a/src/util.h b/src/util.h index 6ee7ffaf9..c6c6f9ca7 100644 --- a/src/util.h +++ b/src/util.h @@ -103,6 +103,7 @@ extern bool fServer; extern std::string strMiscWarning; extern bool fNoListen; extern bool fLogTimestamps; +extern bool fUBI; extern volatile bool fReopenDebugLog; void RandAddSeed(); From ce117f147a86ca4a9ad91db9a59aa7387183dc0a Mon Sep 17 00:00:00 2001 From: Bjarki Gunnarsson Date: Fri, 7 Aug 2020 14:09:34 +0000 Subject: [PATCH 02/11] fix ubi algo --- src/ubi.cpp | 46 +++++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/src/ubi.cpp b/src/ubi.cpp index ab3943618..b8f5fd469 100644 --- a/src/ubi.cpp +++ b/src/ubi.cpp @@ -10,17 +10,13 @@ #include #include -/* To the reader: - * We calculate the next batch of UBI recipients for every thread, - * but we can do it only for each block height when someone has - * actually been paid. - * - * Could move initialization to init.cpp to conform to the other code - * but that's annoying. - */ - using namespace std; +CCriticalSection cs_currentheight; +unsigned int nCurrentHeight = 0; + +vector vBatch; + // compare recipients only via block-last-paid, the address is irrelevant bool operator<(const Recipient& lhs, const Recipient& rhs) { @@ -49,7 +45,6 @@ static void InitCirculation() if (!addressfile.good()) LogPrintf("UBI::InitCirculation() couldn't read ubi_addresses file, not paying any UBI\n"); - string ln; while (getline(addressfile, ln)) { @@ -60,6 +55,8 @@ static void InitCirculation() // user has not been paid, so he is initialized with the height 0 vRecipients.push_back({0, CBitcoinAddress(ln)}); } + + vBatch.assign(min(nBatchSize, vRecipients.size()), CScript()); } // goes through vRecipients and selects the addresses that haven't been paid @@ -70,33 +67,28 @@ vector NextBatch(const unsigned int nHeight) { boost::call_once(&InitCirculation, ubiInitFlag); - int stop = min(vRecipients.size(), nBatchSize); + LOCK(cs_currentheight); + if (nHeight == nCurrentHeight) + return vBatch; - vector batch(vRecipients.begin(), vRecipients.begin()+stop); + nCurrentHeight = nHeight; + + int stop = min(vRecipients.size(), nBatchSize); // choose the recipients with the lowest lastpaid values - for (auto &r : vRecipients) + for (int i = 0; i < stop; i++) { // using our operator< get the iterator of the recipient in batch that // has been paid most recently - auto it = max_element(batch.begin(), batch.end()); + auto it = min_element(vRecipients.begin(), vRecipients.end()); + it->lastpaid = nHeight; - if (r < *it) - { - *it = r; - r.lastpaid = nHeight; - } - } - - vector ret; - for (auto r : batch) - { CScript s; - s.SetDestination(r.address.Get()); - ret.push_back(s); + s.SetDestination(it->address.Get()); + vBatch[i] = s; } - return ret; + return vBatch; } // Similar to GetBlockValueDividends but doesn't depend on block height From 5ec5e7ea501ba91f5b41bb70e67e000f87272cab Mon Sep 17 00:00:00 2001 From: Bjarki Gunnarsson Date: Wed, 12 Aug 2020 10:39:09 +0000 Subject: [PATCH 03/11] comment and rename variables --- src/ubi.cpp | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/src/ubi.cpp b/src/ubi.cpp index b8f5fd469..a03292115 100644 --- a/src/ubi.cpp +++ b/src/ubi.cpp @@ -12,23 +12,32 @@ using namespace std; -CCriticalSection cs_currentheight; +CCriticalSection cs_ubi; + +// the height of vBatch, if the external blockheight changes then vBatch +// is updated unsigned int nCurrentHeight = 0; +// where we store our batch between blockchain updates vector vBatch; -// compare recipients only via block-last-paid, the address is irrelevant +// compare first using lastpaid, and then using the CBitcoinAddress +// builtin comparator bool operator<(const Recipient& lhs, const Recipient& rhs) { - return lhs.lastpaid < rhs.lastpaid; + if (lhs.lastpaid != rhs.lastpaid) + return lhs.lastpaid < rhs.lastpaid; + else + return lhs.address < rhs.address; } -// our list of recipients +// our list of recipients from vRecipients, also only updated on a new blockchain vector vRecipients; // how many recipient are paid per block const size_t nBatchSize = 5; +// remove once we move to servicelist, only for reading ubi_addresses static boost::once_flag ubiInitFlag = BOOST_ONCE_INIT; namespace UBI @@ -61,22 +70,23 @@ static void InitCirculation() // goes through vRecipients and selects the addresses that haven't been paid // for the longest time. -// in: nHeight, height of the block that pays the addresses -// return: vector of the CScript's that pay the block's ubi recipients vector NextBatch(const unsigned int nHeight) { boost::call_once(&InitCirculation, ubiInitFlag); - LOCK(cs_currentheight); + LOCK(cs_ubi); + // probably called by a sister thread, no need to compute everything + // all over again for the same heigth if (nHeight == nCurrentHeight) return vBatch; nCurrentHeight = nHeight; - int stop = min(vRecipients.size(), nBatchSize); - - // choose the recipients with the lowest lastpaid values - for (int i = 0; i < stop; i++) + // choose the recipients with the lowest lastpaid values. + // if we just paid nbatchsize many recipients some would get paid multiple + // times without us knowing who, so we cap it at vRecipients.size() if it's + // lower than nBatchSize + for (unsigned int i = 0; i < min(vRecipients.size(), nBatchSize); i++) { // using our operator< get the iterator of the recipient in batch that // has been paid most recently @@ -91,17 +101,14 @@ vector NextBatch(const unsigned int nHeight) return vBatch; } -// Similar to GetBlockValueDividends but doesn't depend on block height -// in: nFees, block fees -// return: dividends per recipient, 0 if there are none +// Similar to GetBlockValueDividends but doesn't depend on block height since we only +// harvest from nFees int64_t GetUBIDividends(const int64_t nFees) { if (vRecipients.empty()) return 0; - int64_t nRecipientCount = min(nBatchSize, vRecipients.size()); - - return (int64_t)(0.9 * nFees) / nRecipientCount; + return (int64_t)(0.9 * nFees) / (int64_t)min(nBatchSize, vRecipients.size()); } } // namespace UBI From 68cdc68ef8ae591886ab80a8c715f9f81e266a61 Mon Sep 17 00:00:00 2001 From: Bjarki Gunnarsson Date: Wed, 19 Aug 2020 11:17:00 +0000 Subject: [PATCH 04/11] minor fixes --- src/ubi.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/ubi.cpp b/src/ubi.cpp index a03292115..7f4422ba8 100644 --- a/src/ubi.cpp +++ b/src/ubi.cpp @@ -1,17 +1,13 @@ #include "ubi.h" #include -#include -#include -#include -#include #include #include -#include using namespace std; +// guards nCurrentHeigth, vBatch and vRecipients CCriticalSection cs_ubi; // the height of vBatch, if the external blockheight changes then vBatch @@ -42,7 +38,6 @@ static boost::once_flag ubiInitFlag = BOOST_ONCE_INIT; namespace UBI { - // read ~/.smileycoin/ubi_addresses and put them into vRecipients // it's alright if there is no file, then it behaves like -ubi=0 static void InitCirculation() @@ -75,11 +70,13 @@ vector NextBatch(const unsigned int nHeight) boost::call_once(&InitCirculation, ubiInitFlag); LOCK(cs_ubi); - // probably called by a sister thread, no need to compute everything - // all over again for the same heigth + // multiple miners run at the same time on the same block so we only need to compute + // the vBatch once for each height, if the height is the same then return the same + // batch if (nHeight == nCurrentHeight) return vBatch; + // update our current height and compute the new vBatch nCurrentHeight = nHeight; // choose the recipients with the lowest lastpaid values. @@ -91,11 +88,13 @@ vector NextBatch(const unsigned int nHeight) // using our operator< get the iterator of the recipient in batch that // has been paid most recently auto it = min_element(vRecipients.begin(), vRecipients.end()); - it->lastpaid = nHeight; CScript s; s.SetDestination(it->address.Get()); vBatch[i] = s; + + // mark it as paid + it->lastpaid = nHeight; } return vBatch; @@ -108,7 +107,7 @@ int64_t GetUBIDividends(const int64_t nFees) if (vRecipients.empty()) return 0; - return (int64_t)(0.9 * nFees) / (int64_t)min(nBatchSize, vRecipients.size()); + return (int64_t)(9 * nFees / 10) / (int64_t)min(nBatchSize, vRecipients.size()); } } // namespace UBI From c15dc03b144abdf0286110857c0722235fb1fd53 Mon Sep 17 00:00:00 2001 From: Bjarki Gunnarsson Date: Mon, 23 Nov 2020 10:40:32 +0000 Subject: [PATCH 05/11] fix getubilist --- src/rpcmisc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index f7e249077..1f5974ecd 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -840,7 +840,7 @@ Value getubilist(const Array& params, bool fHelp) ServiceList.GetServiceAddresses(services); bool isUbi = false; for(std::multiset< std::pair > >::const_iterator it = services.begin(); it!=services.end(); it++ ) { - if (get<2>(it->second) == "2") { + if (get<2>(it->second) == "UBI") { isUbi = true; } } @@ -1193,4 +1193,4 @@ Value verifymessage(const Array& params, bool fHelp) return (pubkey.GetID() == keyID); } -#pragma clang diagnostic pop \ No newline at end of file +#pragma clang diagnostic pop From 7efc8c0151a53daeea07f982c65ad96c3ef584fd Mon Sep 17 00:00:00 2001 From: Bjarki Gunnarsson Date: Mon, 23 Nov 2020 11:27:20 +0000 Subject: [PATCH 06/11] make ubi use ubilist and fix getserviceaddresses --- src/rpcmisc.cpp | 6 ++++++ src/ubi.cpp | 23 ++++++++--------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index 1f5974ecd..f582f6acf 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -737,6 +737,7 @@ Value getserviceaddresses(const Array& params, bool fHelp) Object root; Array tservices; /* TicketSales */ + Array uservices; /* UBI */ Array bservices; /* BookChapter */ Array nservices; /* NPO */ Array dservices; /* DEX */ @@ -755,6 +756,10 @@ Value getserviceaddresses(const Array& params, bool fHelp) name_address.push_back(Pair("name", get<1>(s->second))); name_address.push_back(Pair("address", s->first)); tservices.push_back(name_address); + } else if (get<2>(s->second) == "UBI") { // "2" + name_address.push_back(Pair("name", get<1>(s->second))); + name_address.push_back(Pair("address", s->first)); + uservices.push_back(name_address); } else if (get<2>(s->second) == "Book Chapter") { // "3" name_address.push_back(Pair("name", get<1>(s->second))); name_address.push_back(Pair("address", s->first)); @@ -775,6 +780,7 @@ Value getserviceaddresses(const Array& params, bool fHelp) } root.push_back(Pair("Ticket Sales", tservices)); + root.push_back(Pair("UBI", uservices)); root.push_back(Pair("Book Chapter", bservices)); root.push_back(Pair("Nonprofit Organization", nservices)); root.push_back(Pair("DEX", dservices)); diff --git a/src/ubi.cpp b/src/ubi.cpp index 7f4422ba8..36f700fa6 100644 --- a/src/ubi.cpp +++ b/src/ubi.cpp @@ -38,26 +38,19 @@ static boost::once_flag ubiInitFlag = BOOST_ONCE_INIT; namespace UBI { -// read ~/.smileycoin/ubi_addresses and put them into vRecipients -// it's alright if there is no file, then it behaves like -ubi=0 static void InitCirculation() { - auto addressfile_path = GetDataDir() / "ubi_addresses"; + std::multiset>> ubilist; - ifstream addressfile(addressfile_path.string()); + ServiceItemList.GetUbiList(ubilist); - if (!addressfile.good()) - LogPrintf("UBI::InitCirculation() couldn't read ubi_addresses file, not paying any UBI\n"); - - string ln; - while (getline(addressfile, ln)) + for (auto r : ubilist) { - // allow empty lines or comments - if (ln[0] == '#' || ln.empty()) - continue; - - // user has not been paid, so he is initialized with the height 0 - vRecipients.push_back({0, CBitcoinAddress(ln)}); + std::string toAddress = get<1>(r.second); + if (toAddress == "" { + vRecipients.push_back({0, CBitcoinAddress(it.first)}); + } } vBatch.assign(min(nBatchSize, vRecipients.size()), CScript()); From 6bec7d5ba0e9ca94c9577f1c9c3779c5bc29821e Mon Sep 17 00:00:00 2001 From: Bjarki Gunnarsson Date: Fri, 27 Nov 2020 18:33:05 +0000 Subject: [PATCH 07/11] add urUBI address --- src/ubi.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ubi.cpp b/src/ubi.cpp index 36f700fa6..d6f8ffb72 100644 --- a/src/ubi.cpp +++ b/src/ubi.cpp @@ -5,6 +5,9 @@ #include +#include "servicelistdb.h" +#include "serviceitemlistdb.h" + using namespace std; // guards nCurrentHeigth, vBatch and vRecipients @@ -47,9 +50,9 @@ static void InitCirculation() for (auto r : ubilist) { - std::string toAddress = get<1>(r.second); - if (toAddress == "" { - vRecipients.push_back({0, CBitcoinAddress(it.first)}); + // the urUBI address + if (get<1>(r.second) == "BLsTgPMirCUmnd3TE5p9rBLQSXBid3KfnT") { + vRecipients.push_back({0, CBitcoinAddress(r.first)}); } } From 8ce45657942356544aa4c93eb5f9d4133d7aa990 Mon Sep 17 00:00:00 2001 From: Bjarki Gunnarsson Date: Fri, 27 Nov 2020 18:41:20 +0000 Subject: [PATCH 08/11] fix a bit --- src/init.cpp | 2 +- src/miner.cpp | 6 ++++-- src/util.cpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index a96779f1c..972204b3c 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -561,7 +561,7 @@ bool AppInit2(boost::thread_group& threadGroup) fServer = GetBoolArg("-server", false); fPrintToConsole = GetBoolArg("-printtoconsole", false); fLogTimestamps = GetBoolArg("-logtimestamps", true); - fUBI = GetBoolArg("-ubi", true); + fUBI = GetBoolArg("-ubi", false); setvbuf(stdout, NULL, _IOLBF, 0); #ifdef ENABLE_WALLET bool fDisableWallet = GetBoolArg("-disablewallet", false); diff --git a/src/miner.cpp b/src/miner.cpp index 82a36c732..8b009b719 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -367,8 +367,10 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, int algo) LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize); - // miner's reward - txNew.vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees*0.10); + // miner's reward, if ubi then we take a 90% of the tx fees + if (fUBI) { + txNew.vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees/10); + } //CTxOut minerTxOut = CTxOut(0, scriptPubKeyIn); CScript richpubkey; if(!RichList.NextRichScriptPubKey(richpubkey)) diff --git a/src/util.cpp b/src/util.cpp index 1af5bcf13..f75718dac 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -97,7 +97,7 @@ bool fServer = false; string strMiscWarning; bool fNoListen = false; bool fLogTimestamps = false; -bool fUBI = true; +bool fUBI = false; volatile bool fReopenDebugLog = false; CClientUIInterface uiInterface; From 8c208379a7472032e2ed52a8522b0e16d5f31e1f Mon Sep 17 00:00:00 2001 From: Bjarki <65368693+bjarki781@users.noreply.github.com> Date: Fri, 27 Nov 2020 22:31:53 +0000 Subject: [PATCH 09/11] Update .gitignore --- .gitignore | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/.gitignore b/.gitignore index 17cbc6cde..c96bcdf52 100644 --- a/.gitignore +++ b/.gitignore @@ -26,19 +26,6 @@ build-aux/m4/ltversion.m4 build-aux/missing build-aux/compile build-aux/test-driver -src/build-aux/config.guess -src/build-aux/config.sub -src/build-aux/depcomp -src/build-aux/install-sh -src/build-aux/ltmain.sh -src/build-aux/libtool.m4 -src/build-aux/lt~obsolete.m4 -src/build-aux/ltoptions.m4 -src/build-aux/ltsugar.m4 -src/build-aux/ltversion.m4 -src/build-aux/missing -src/build-aux/compile -src/build-aux/test-driver config.log config.status configure From daff56b3087ab67b0f2ed035c60bd6f9385eae2c Mon Sep 17 00:00:00 2001 From: Bjarki Gunnarsson Date: Fri, 28 May 2021 15:24:51 +0000 Subject: [PATCH 10/11] Revert "Update .gitignore" This reverts commit 8c208379a7472032e2ed52a8522b0e16d5f31e1f. --- .gitignore | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.gitignore b/.gitignore index c96bcdf52..17cbc6cde 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,19 @@ build-aux/m4/ltversion.m4 build-aux/missing build-aux/compile build-aux/test-driver +src/build-aux/config.guess +src/build-aux/config.sub +src/build-aux/depcomp +src/build-aux/install-sh +src/build-aux/ltmain.sh +src/build-aux/libtool.m4 +src/build-aux/lt~obsolete.m4 +src/build-aux/ltoptions.m4 +src/build-aux/ltsugar.m4 +src/build-aux/ltversion.m4 +src/build-aux/missing +src/build-aux/compile +src/build-aux/test-driver config.log config.status configure From 17fd70eff79ff742db71a5bc974b5514ce03f589 Mon Sep 17 00:00:00 2001 From: Bjarki Gunnarsson Date: Tue, 1 Jun 2021 23:37:40 +0000 Subject: [PATCH 11/11] add nplist functionality --- src/coins.cpp | 33 ++++++++- src/coins.h | 13 ++++ src/init.cpp | 28 +++++++ src/main.cpp | 69 +++++++++++++++++- src/main.h | 1 + src/rpcmisc.cpp | 149 ++++++++++++++++++++++++++++++++------ src/rpcserver.cpp | 2 + src/rpcserver.h | 1 + src/serviceitemlistdb.cpp | 149 +++++++++++++++++++++++++++++++++++++- src/serviceitemlistdb.h | 15 +++- src/servicelistdb.cpp | 6 +- src/txdb.cpp | 71 ++++++++++++++++++ src/txdb.h | 6 ++ 13 files changed, 515 insertions(+), 28 deletions(-) diff --git a/src/coins.cpp b/src/coins.cpp index 0c51c11df..c467e07b8 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -63,6 +63,8 @@ bool CCoinsView::GetDexList(const std::string &key, std::tuple &value) { return false; } bool CCoinsView::GetBookList(const std::string &key, std::tuple &value) { return false; } bool CCoinsView::SetBookList(const std::string &key, const std::tuple &value) { return false; } +bool CCoinsView::GetNPList(const std::string &key, std::tuple &value) { return false; } +bool CCoinsView::SetNPList(const std::string &key, const std::tuple &value) { return false; } bool CCoinsView::HaveCoins(const uint256 &txid) { return false; } uint256 CCoinsView::GetBestBlock() { return uint256(0); } bool CCoinsView::SetBestBlock(const uint256 &hashBlock) { return false; } @@ -72,6 +74,7 @@ bool CCoinsView::BatchWrite(const std::map &mapCoins, const std const std::map > &mapServiceUbiList, const std::map > &mapServiceDexList, const std::map > &mapServiceBookList, + const std::map > &mapServiceNPList, const uint256 &hashBlock) { return false; } bool CCoinsView::GetStats(CCoinsStats &stats) { return false; } @@ -91,6 +94,8 @@ bool CCoinsViewBacked::GetDexList(const std::string &key, std::tuple &value) { return base->SetDexList(key, value); } bool CCoinsViewBacked::GetBookList(const std::string &key, std::tuple &value) { return base->GetBookList(key, value); } bool CCoinsViewBacked::SetBookList(const std::string &key, const std::tuple &value) { return base->SetBookList(key, value); } +bool CCoinsViewBacked::GetNPList(const std::string &key, std::tuple &value) { return base->GetNPList(key, value); } +bool CCoinsViewBacked::SetNPList(const std::string &key, const std::tuple &value) { return base->SetNPList(key, value); } bool CCoinsViewBacked::HaveCoins(const uint256 &txid) { return base->HaveCoins(txid); } uint256 CCoinsViewBacked::GetBestBlock() { return base->GetBestBlock(); } bool CCoinsViewBacked::SetBestBlock(const uint256 &hashBlock) { return base->SetBestBlock(hashBlock); } @@ -101,7 +106,8 @@ bool CCoinsViewBacked::BatchWrite(const std::map &mapCoins, con const std::map > &mapServiceUbiList, const std::map > &mapServiceDexList, const std::map > &mapServiceBookList, - const uint256 &hashBlock) { return base->BatchWrite(mapCoins, mapAddressInfo, mapServiceInfo, mapServiceTicketList, mapServiceUbiList, mapServiceDexList, mapServiceBookList, hashBlock); } + const std::map > &mapServiceNPList, + const uint256 &hashBlock) { return base->BatchWrite(mapCoins, mapAddressInfo, mapServiceInfo, mapServiceTicketList, mapServiceUbiList, mapServiceDexList, mapServiceBookList, mapServiceNPList, hashBlock); } bool CCoinsViewBacked::GetStats(CCoinsStats &stats) { return base->GetStats(stats); } CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), hashBlock(0) { } @@ -230,6 +236,25 @@ bool CCoinsViewCache::SetBookList(const std::string &key, const std::tuple &value) { + std::map >::iterator it = cacheServiceNPList.find(key); + + if(it!=cacheServiceNPList.end()) { + value = it->second; + return true; + } + if(base->GetNPList(key,value)) { + cacheServiceNPList[key] = value; + return true; + } + return false; +} + +bool CCoinsViewCache::SetNPList(const std::string &key, const std::tuple &value) { + cacheServiceNPList[key] = value; + return true; +} + std::map::iterator CCoinsViewCache::FetchCoins(const uint256 &txid) { std::map::iterator it = cacheCoins.lower_bound(txid); if (it != cacheCoins.end() && it->first == txid) @@ -275,6 +300,7 @@ bool CCoinsViewCache::BatchWrite(const std::map &mapCoins, const std::map > &mapServiceUbiList, const std::map > &mapServiceDexList, const std::map > &mapServiceBookList, + const std::map > &mapServiceNPList, const uint256 &hashBlockIn) { for (std::map::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++) cacheCoins[it->first] = it->second; @@ -290,13 +316,15 @@ bool CCoinsViewCache::BatchWrite(const std::map &mapCoins, cacheServiceDexList[it->first] = it->second; for (std::map >::const_iterator it = mapServiceBookList.begin(); it != mapServiceBookList.end(); it++) cacheServiceBookList[it->first] = it->second; + for (std::map >::const_iterator it = mapServiceNPList.begin(); it != mapServiceNPList.end(); it++) + cacheServiceNPList[it->first] = it->second; hashBlock = hashBlockIn; return true; } bool CCoinsViewCache::Flush() { - bool fOk = base->BatchWrite(cacheCoins, cacheAddressInfo, cacheServiceInfo, cacheServiceTicketList, cacheServiceUbiList, cacheServiceDexList, cacheServiceBookList, hashBlock); + bool fOk = base->BatchWrite(cacheCoins, cacheAddressInfo, cacheServiceInfo, cacheServiceTicketList, cacheServiceUbiList, cacheServiceDexList, cacheServiceBookList, cacheServiceNPList, hashBlock); if (fOk) { cacheCoins.clear(); cacheAddressInfo.clear(); @@ -305,6 +333,7 @@ bool CCoinsViewCache::Flush() { cacheServiceUbiList.clear(); cacheServiceDexList.clear(); cacheServiceBookList.clear(); + cacheServiceNPList.clear(); } return fOk; } diff --git a/src/coins.h b/src/coins.h index 611f360ab..9c49bcbbc 100644 --- a/src/coins.h +++ b/src/coins.h @@ -248,6 +248,11 @@ class CCoinsView //Modify the balance of and height where a given scriptPubKey was last used - servicebooklist virtual bool SetBookList(const std::string &key, const std::tuple &value); + virtual bool GetNPList(const std::string &key, std::tuple &value); + + //Modify the balance of and height where a given scriptPubKey was last used - servicebooklist + virtual bool SetNPList(const std::string &key, const std::tuple &value); + //Just check whether we have data for a given txid. virtual bool HaveCoins(const uint256 &txid); @@ -264,6 +269,7 @@ class CCoinsView const std::map > &mapServiceUbiList, const std::map > &mapServiceDexList, const std::map > &mapServiceBookList, + const std::map > &mapServiceNPList, const uint256 &hashBlock); //Calculate statistics about the unspent transaction output set @@ -296,6 +302,8 @@ class CCoinsViewBacked : public CCoinsView bool SetDexList(const std::string &key, const std::tuple &value); bool GetBookList(const std::string &key, std::tuple &value); bool SetBookList(const std::string &key, const std::tuple &value); + bool GetNPList(const std::string &key, std::tuple &value); + bool SetNPList(const std::string &key, const std::tuple &value); bool HaveCoins(const uint256 &txid); uint256 GetBestBlock(); bool SetBestBlock(const uint256 &hashBlock); @@ -306,6 +314,7 @@ class CCoinsViewBacked : public CCoinsView const std::map > &mapServiceUbiList, const std::map > &mapServiceDexList, const std::map > &mapServiceBookList, + const std::map > &mapServiceNPList, const uint256 &hashBlock); bool GetStats(CCoinsStats &stats); }; @@ -323,6 +332,7 @@ class CCoinsViewCache : public CCoinsViewBacked std::map > cacheServiceUbiList; std::map > cacheServiceDexList; std::map > cacheServiceBookList; + std::map > cacheServiceNPList; public: CCoinsViewCache(CCoinsView &baseIn, bool fDummy = false); @@ -342,6 +352,8 @@ class CCoinsViewCache : public CCoinsViewBacked bool SetDexList(const std::string &key, const std::tuple &value); bool GetBookList(const std::string &key, std::tuple &value); bool SetBookList(const std::string &key, const std::tuple &value); + bool GetNPList(const std::string &key, std::tuple &value); + bool SetNPList(const std::string &key, const std::tuple &value); bool HaveCoins(const uint256 &txid); uint256 GetBestBlock(); bool SetBestBlock(const uint256 &hashBlock); @@ -351,6 +363,7 @@ class CCoinsViewCache : public CCoinsViewBacked const std::map > &mapServiceUbiList, const std::map > &mapServiceDexList, const std::map > &mapServiceBookList, + const std::map > &mapServiceNPList, const uint256 &hashBlock); //Return a modifiable reference to a CCoins. Check HaveCoins first. diff --git a/src/init.cpp b/src/init.cpp index 972204b3c..df6d4f2f3 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -892,6 +892,11 @@ bool AppInit2(boost::thread_group& threadGroup) break; } + if (!InitServiceNPList(*pcoinsdbview)) { + strLoadError = _("Error initializing service np list. You need to rebuild the database using -reindex"); + break; + } + // Reading rich addresses into memory if(!pcoinsdbview -> GetRichAddresses(RichList)) { strLoadError = _("Error loading rich list"); @@ -928,6 +933,12 @@ bool AppInit2(boost::thread_group& threadGroup) break; } + // reading npos addresses into memory + if(!pcoinsdbview -> GetNPList(ServiceItemList)) { + strLoadError = _("Error loading service np list"); + break; + } + // Initialize the block index (no-op if non-empty database was already loaded) if (!InitBlockIndex()) { strLoadError = _("Error initializing block database"); @@ -982,6 +993,13 @@ bool AppInit2(boost::thread_group& threadGroup) ServiceItemList.SetForked(fFork); } + if(!pblocktree -> ReadServiceNPListFork(fFork)) { + strLoadError = _("Error reading service np chapter list fork status"); + break; + } else { + ServiceItemList.SetForked(fFork); + } + uiInterface.InitMessage(_("Verifying blocks...")); if (!VerifyDB(GetArg("-checklevel", 3), GetArg("-checkblocks", 288))) { @@ -1049,6 +1067,16 @@ bool AppInit2(boost::thread_group& threadGroup) } } + if(fFork) { + if(!ServiceItemList.UpdateNPListHeights()) { + strLoadError = _("Error rollbacking NP chapter list heights"); + break; + } + else { + ServiceItemList.SetForked(false); + } + } + } catch(std::exception &e) { if (fDebug) LogPrintf("%s\n", e.what()); strLoadError = _("Error opening block database"); diff --git a/src/main.cpp b/src/main.cpp index 602bc19a5..4c94c37f8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1820,6 +1820,7 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex std::map > serviceUbiList; std::map > serviceDexList; std::map > serviceBookList; + std::map > serviceNPList; // undo transactions in reverse order for (int i = block.vtx.size() - 1; i >= 0; i--) { @@ -1868,7 +1869,8 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex if (sAddress.IsValid() && !ServiceList.IsService(asciiAddress) && serviceName.length() <= 50 && (hexToAscii(serviceType) == "1" || hexToAscii(serviceType) == "2" || hexToAscii(serviceType) == "3"|| hexToAscii(serviceType) == "4"|| - hexToAscii(serviceType) == "5"|| hexToAscii(serviceType) == "6" || hexToAscii(serviceType) == "7")) { + hexToAscii(serviceType) == "5"|| hexToAscii(serviceType) == "6" || hexToAscii(serviceType) == "7" + || hexToAscii(serviceType) == "8")) { std::tuple value; if (!view.GetServiceInfo(asciiAddress, value)) { return state.Abort(_("Failed to read service index")); @@ -1988,6 +1990,29 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex } } } + // New Np + // If the string starts with "NN" + else if (hexData.substr(0, 4) == "4e4e") { + std::string newDex = hexData.substr(4, hexString.size()); + std::vector strs = splitString(newDex, "20"); + // The string has to have 2 params to be valid as a np and saved into the db + if (strs.size() == 2) { + std::string npAddress = strs.at(0); + std::string npName = strs.at(1); + std::string asciiAddress = hexToAscii(npAddress); + CBitcoinAddress nAddress = CBitcoinAddress(asciiAddress); + if (nAddress.IsValid() && npName.length() <= 60 && ServiceList.IsService(toAddress)) { + std::tuple value; + if(!view.GetNPList(asciiAddress, value)) + return state.Abort(_("Failed to read np index")); + else { + value = std::make_tuple("NN", toAddress, hexToAscii(npName)); + assert(view.SetNPList(asciiAddress, value)); + serviceNPList[asciiAddress]=value; + } + } + } + } // New book chapter // If the string starts with "NB" else if (hexData.substr(0, 4) == "4e42") { @@ -2201,6 +2226,10 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex return state.Abort(_("Failed to update book chapter list")); } + if(!ServiceItemList.UpdateNPList(serviceNPList)) { + return state.Abort(_("Failed to update np chapter list")); + } + return fClean; } @@ -2293,6 +2322,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C std::map > serviceUbiList; std::map > serviceDexList; std::map > serviceBookList; + std::map > serviceNPList; for (unsigned int i = 0; i < block.vtx.size(); i++) { @@ -2392,7 +2422,8 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C if (sAddress.IsValid() && !ServiceList.IsService(asciiAddress) && serviceName.length() <= 50 && (hexToAscii(serviceType) == "1" || hexToAscii(serviceType) == "2" || hexToAscii(serviceType) == "3"|| hexToAscii(serviceType) == "4"|| - hexToAscii(serviceType) == "5"|| hexToAscii(serviceType) == "6" || hexToAscii(serviceType) == "7")) { + hexToAscii(serviceType) == "5"|| hexToAscii(serviceType) == "6" || hexToAscii(serviceType) == "7" + || hexToAscii(serviceType) == "8")) { std::tuple value; value = std::make_tuple("NS", hexToAscii(serviceName), hexToAscii(serviceType)); assert(view.SetServiceInfo(asciiAddress, value)); @@ -2493,6 +2524,24 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C } } } + // If the string starts with "NN" (new np) + else if (hexData.substr(0, 4) == "4e4e") { + std::string newNP = hexData.substr(4, hexString.size()); + std::vector strs = splitString(newNP, "20"); + // The string has to have 2 params to be valid as a dex and saved into the db + if (strs.size() == 2) { + std::string npAddress = strs.at(0); + std::string npName = strs.at(1); + std::string asciiAddress = hexToAscii(npAddress); + CBitcoinAddress nAddress = CBitcoinAddress(asciiAddress); + if (nAddress.IsValid() && npName.length() <= 60 && ServiceList.IsService(toAddress)) { + std::tuple value; + value = std::make_tuple("NN", toAddress, hexToAscii(npName)); + assert(view.SetNPList(asciiAddress, value)); + serviceNPList[asciiAddress]=value; + } + } + } // If the string starts with "NB" (new book chapter) else if (hexData.substr(0, 4) == "4e42") { std::string newBookChapter = hexData.substr(4, hexString.size()); @@ -2585,6 +2634,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C } } } + std::cout << hexData.substr(0, 4) << std::endl; } } } @@ -4079,6 +4129,21 @@ bool InitServiceBookList(CCoinsView &dbview) } +bool InitServiceNPList(CCoinsView &dbview) +{ + LOCK(cs_main); + if (fReindex || chainActive.Genesis() == NULL) { + if(!dbview.SetBookList(string("np"), std::make_tuple("1", "0", "0"))) { + return false; } + pblocktree->WriteFlag("nplist", true); + } + bool dummy; + if(!pblocktree->ReadFlag("nplist", dummy)) + return false; + return true; + +} + void PrintBlockTree() { AssertLockHeld(cs_main); diff --git a/src/main.h b/src/main.h index 5cbe0fa63..162e56844 100644 --- a/src/main.h +++ b/src/main.h @@ -156,6 +156,7 @@ bool InitServiceTicketList(CCoinsView &dbview); bool InitServiceUbiList(CCoinsView &dbview); bool InitServiceDexList(CCoinsView &dbview); bool InitServiceBookList(CCoinsView &dbview); +bool InitServiceNPList(CCoinsView &dbview); /** Load the block tree and coins database from disk */ bool LoadBlockIndex(); /** Unload database information */ diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index f582f6acf..f666c15ad 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -218,6 +218,96 @@ Value adddex(const Array& params, bool fHelp) return wtx.GetHash().GetHex(); } +Value addnpo(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 3) + throw runtime_error( + "addnpo \"nptype\" \"npaddress\" \"npname\" \n" + "\n Add new non-profit address to a non-profit group/type.\n" + + HelpRequiringPassphrase() + + "\nArguments:\n" + "1. \"nptype\" (string, required) The DEX service name associated with the new DEX address.\n" + "2. \"npaddress\" (string, required) The smileycoin DEX address associated with the DEX service.\n" + "3. \"npname\" (string, required) A short description of the DEX. \n" + + "\nResult:\n" + "\"transactionid\" (string) The transaction id.\n" + "\nExamples:\n" + + HelpExampleCli("adddex", "SmileyDEX 1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd dexdescription") + + HelpExampleCli("adddex", "SmileyDEX 1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd dexdescription") + + HelpExampleRpc("adddex", "SmileyDEX 1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd dexdescription") + ); + + std::string serviceName = params[0].get_str(); + std::string npAddress = params[1].get_str(); + std::string npName = params[2].get_str(); + + CBitcoinAddress address(npAddress); + if (!address.IsValid()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Smileycoin address"); + } else if (ServiceItemList.IsNP(npAddress)) { + throw runtime_error("The entered address is already on the non-profit list. Please use another address."); + } else if (npName.length() > 30) { + throw runtime_error("Non-profit name cannot be more than 30 characters long."); + } + + // Amount + int64_t nValue = 1*COIN; + int64_t DEFAULT_AMOUNT = 0; + + vector > vecSend; + + std::multiset>> myServices; + ServiceList.GetMyServiceAddresses(myServices); + + std::string npServiceAddress = ""; + // Send new ticket transaction to corresponding service address + for(std::set< std::pair< std::string, std::tuple > >::const_iterator it = myServices.begin(); it!=myServices.end(); it++ ) + { + if(serviceName == get<1>(it->second)) { + npServiceAddress = it->first; + } + } + + if (!ServiceList.IsService(npServiceAddress)) { + throw runtime_error("The entered non-profit group name cannot be found on service list."); + } + + // Parse Smileycoin address + CBitcoinAddress dServiceAddress(npServiceAddress); + CScript scriptPubKey; + scriptPubKey.SetDestination(dServiceAddress.Get()); + + // Pay 1 SMLY to own np service address + vecSend.push_back(make_pair(scriptPubKey, nValue)); + + vector str; + int64_t amount = 0; + + std::string txData = HexStr("NN " + npAddress + " " + npName, false); + str.push_back(txData); + vector data = ParseHexV(str[0], "Data"); + + // Create op_return script in the form -> NN npaddress npname + vecSend.push_back(make_pair(CScript() << OP_RETURN << data, max(DEFAULT_AMOUNT, amount) * COIN)); + + CWalletTx wtx; + + EnsureWalletIsUnlocked(); + + // Send + CReserveKey keyChange(pwalletMain); + int64_t nFeeRequired = 0; + string strFailReason; + bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, strFailReason); + if (!fCreated) + throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason); + if (!pwalletMain->CommitTransaction(wtx, keyChange)) + throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed"); + + return wtx.GetHash().GetHex(); +} + Value addubi(const Array& params, bool fHelp) { if (fHelp || params.size() != 2) @@ -410,6 +500,7 @@ Value createservice(const Array& params, bool fHelp) "5 = Nonprofit Organization \n" "6 = DEX \n" "7 = Survey \n \n" + "8 = Non-profit groups \n \n" "\nResult:\n" "\"transactionid\" (string) The transaction id.\n" @@ -425,13 +516,15 @@ Value createservice(const Array& params, bool fHelp) // VANTAR CHECK FYRIR LENGD + int intServiceType = stoi(serviceType); + CBitcoinAddress address(serviceAddress); if (!address.IsValid()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Smileycoin address"); } else if (ServiceList.IsService(serviceAddress)) { throw runtime_error("The entered address is already on service list. Please use another address."); - } else if (serviceType != "1" || serviceType != "2" || serviceType != "3"|| serviceType != "4"|| serviceType != "5" || serviceType != "6" || serviceType != "7") { - throw runtime_error("Invalid service type. Please choose a type between 1 - 7."); + } else if (intServiceType < 1 || intServiceType > 8 ) { + throw runtime_error("Invalid service type. Please choose a type between 1 - 8."); } // Amount @@ -742,6 +835,7 @@ Value getserviceaddresses(const Array& params, bool fHelp) Array nservices; /* NPO */ Array dservices; /* DEX */ Array sservices; /* Survey */ + Array nposervices; /* NP groups */ Object name_address; std::multiset>> services; @@ -775,7 +869,11 @@ Value getserviceaddresses(const Array& params, bool fHelp) } else if (get<2>(s->second) == "Survey") { // "7" name_address.push_back(Pair("name", get<1>(s->second))); name_address.push_back(Pair("address", s->first)); - sservices.push_back(name_address); + nservices.push_back(name_address); + } else if (get<2>(s->second) == "Non-profit Group") { // "8" + name_address.push_back(Pair("name", get<1>(s->second))); + name_address.push_back(Pair("address", s->first)); + nposervices.push_back(name_address); } } @@ -785,6 +883,7 @@ Value getserviceaddresses(const Array& params, bool fHelp) root.push_back(Pair("Nonprofit Organization", nservices)); root.push_back(Pair("DEX", dservices)); root.push_back(Pair("Survey", sservices)); + root.push_back(Pair("Non-profit Group", nposervices)); return root; } @@ -896,45 +995,53 @@ Value getdexlist(const Array& params, bool fHelp) return obj; } -Value getnpolist(const Array& params, bool fHelp) +Value getbooklist(const Array& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error("getnpolist\n" - "Returns all non profit organization addresses\n" + throw runtime_error("getbooklist \"address\"\n" + "Returns all book chapters that belong to the specified book service address\n" ); Object obj; - /*std::multiset>> info; - - ServiceItemList.GetNpoList(info); + std::multiset>> info; + ServiceItemList.GetBookList(info); - for(std::set< std::pair< CScript, std::tuple > >::const_iterator it = info.begin(); it!=info.end(); it++ ) + //TODO bæta við book name, book author og year + for(std::set< std::pair< std::string, std::tuple > >::const_iterator it = info.begin(); it!=info.end(); it++ ) { - obj.push_back(Pair("Npo name: ", get<1>(it->second))); - obj.push_back(Pair("Npo address: ", get<2>(it->second))); - }*/ + obj.push_back(Pair("Chapter Number: ", get<2>(it->second))); + obj.push_back(Pair("Chapter Address: ", it->first)); + } return obj; } -Value getbooklist(const Array& params, bool fHelp) +Value getnpolist(const Array& params, bool fHelp) { if (fHelp || params.size() != 1) - throw runtime_error("getbooklist \"address\"\n" - "Returns all book chapters that belong to the specified book service address\n" + throw runtime_error("getnpolist \"address\"\n" + "Returns all nps that belong to the service/type of np\n" ); + CBitcoinAddress address = CBitcoinAddress(params[0].get_str()); + if(!address.IsValid()) + throw runtime_error("Not a valid Smileycoin address"); + + std::multiset > > services; + ServiceList.GetServiceAddresses(services); Object obj; + std::multiset>> info; - ServiceItemList.GetBookList(info); + ServiceItemList.GetNPList(info); - //TODO bæta við book name, book author og year - for(std::set< std::pair< std::string, std::tuple > >::const_iterator it = info.begin(); it!=info.end(); it++ ) + for(std::set< std::pair< std::string, std::tuple > >::const_iterator it = info.begin(); it!=info.end(); it++) { - obj.push_back(Pair("Chapter Number: ", get<2>(it->second))); - obj.push_back(Pair("Chapter Address: ", it->first)); + if (toAddress == address.ToString()) { + obj.push_back(Pair("Non-profit name: ", get<2>(it->second))); + obj.push_back(Pair("Non-profit address: ", it->first)); + } } return obj; diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index c4999d599..9b7de719f 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -239,6 +239,7 @@ static const CRPCCommand vRPCCommands[] = /* Block chain and UTXO */ { "adddex", &adddex, false, false, false }, + { "addnpo", &addnpo, false, false, false }, { "addubi", &addubi, false, false, false }, { "addchapter", &addchapter, false, false, false }, { "getaddressinfo", &getaddressinfo, false, false, false }, @@ -253,6 +254,7 @@ static const CRPCCommand vRPCCommands[] = { "getdexlist", &getdexlist, false, false, false }, { "getnpolist", &getnpolist, false, false, false }, { "getbooklist", &getbooklist, false, false, false }, + { "getnpolist", &getnpolist, false, false, false }, { "getblockchaininfo", &getblockchaininfo, true, false, false }, { "getbestblockhash", &getbestblockhash, true, false, false }, { "getblockcount", &getblockcount, true, false, false }, diff --git a/src/rpcserver.h b/src/rpcserver.h index 91284fd8b..903e98d43 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -134,6 +134,7 @@ extern json_spirit::Value dumpwallet(const json_spirit::Array& params, bool fHel extern json_spirit::Value importwallet(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value adddex(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value addnpo(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value addubi(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value addchapter(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getrichaddresses(const json_spirit::Array& params, bool fHelp); diff --git a/src/serviceitemlistdb.cpp b/src/serviceitemlistdb.cpp index d8f6eddaf..b699f8dbe 100644 --- a/src/serviceitemlistdb.cpp +++ b/src/serviceitemlistdb.cpp @@ -39,6 +39,10 @@ inline std::string ChapterAction(const CServiceBook &ai) {return get<0>(ai);} inline std::string ChapterToAddress(const CServiceBook &ai) {return get<1>(ai);} inline std::string ChapterNum(const CServiceBook &ai) {return get<2>(ai);} +inline std::string NPAction(const CServiceNP &ai) {return get<0>(ai);} +inline std::string NPToAddress(const CServiceNP &ai) {return get<1>(ai);} +inline std::string NPDescription(const CServiceNP &ai) {return get<2>(ai);} + bool CServiceItemList::SetForked(const bool &fFork) { fForked = fFork; @@ -604,4 +608,147 @@ bool CServiceItemList::IsChapter(std::string address) { } } return false; -} \ No newline at end of file +} + +bool CServiceItemList::UpdateNPList(const std::map > &map) +{ + for(std::map >::const_iterator it = map.begin(); it!= map.end(); it++) + { + std::cout << get<2>(it->second) << std::endl; + + if (get<0>(it->second) == "DN") { // If op_return begins with DN (delete np) + mapServiceNPList::iterator itNP = naddresses.find(it->first); + // If key is found in dex list + if (itNP != naddresses.end()) { + naddresses.erase(itNP); + } + } else if (get<0>(it->second) == "NN") { // If op_return begins with NN (new np) + naddresses.insert(*it); + } + } + return true; +} + +// The heights need to be rolled back before new blocks are connected if any were disconnected. +// TODO: We should try to get rid of this and write the height undo information to the disk instead. +bool CServiceItemList::UpdateNPListHeights() +{ + if(!fForked) + return true; + + CBlockIndex* pindexSeek = mapBlockIndex.find(pcoinsTip->GetBestBlock())->second; + if(!chainActive.Contains(pindexSeek)) { + return false; + } + + CBlock block; + std::map > npItem; + mapServiceNPList mforkedServiceNPList; + + for(mapServiceNPList::const_iterator it = naddresses.begin(); it!=naddresses.end(); it++) + { + if (get<0>(it->second) == "DN") { // If op_return begins with DN (delete np) + mapServiceNPList::iterator itNP = naddresses.find(it->first); + // If key is found in dex list + if (itNP != naddresses.end()) { + naddresses.erase(itNP); + } + } else if (get<0>(it->second) == "NN") { // If op_return begins with NN (new np) + naddresses.insert(*it); + } + } + + if(fDebug) { + LogPrintf("%d addresses seen at fork and need to be relocated\n", mforkedServiceNPList.size()); + } + + while(pindexSeek->pprev && !mforkedServiceNPList.empty()) + { + + // return false; + + ReadBlockFromDisk(block,pindexSeek); + block.BuildMerkleTree(); + BOOST_FOREACH(const CTransaction &tx, block.vtx) + { + for(unsigned int j = 0; j < tx.vout.size(); j++) + { + CScript key = tx.vout[j].scriptPubKey; + /*mapServiceNPList::iterator it = mforkedServiceNPList.find(key); + if(it == mforkedServiceNPList.end()) + continue; + + dexItem.insert(std::make_pair(key, std::make_tuple(NPToAddress(it), NPAddress(it), NPDescription(it)))); + mforkedServiceNPList.erase(it);*/ + if(fDebug) { + CTxDestination dest; + ExtractDestination(key, dest); + CBitcoinAddress addr; + addr.Set(dest); + LogPrintf("%s found at height %d\n",addr.ToString(),pindexSeek->nHeight); + } + } + } + + CBlockUndo undo; + CDiskBlockPos pos = pindexSeek ->GetUndoPos(); + if (undo.ReadFromDisk(pos, pindexSeek->pprev->GetBlockHash())) //TODO: hvenær klikkar þetta? + { + for (unsigned int i=0; ifirst, std::make_tuple(NPToAddress(it), NPAddress(it), NPDescription(it)))); + mforkedServiceNPList.erase(it);*/ + if(fDebug) { + CTxDestination dest; + ExtractDestination(key, dest); + CBitcoinAddress addr; + addr.Set(dest); + LogPrintf("%s found at height %d\n",addr.ToString(),pindexSeek->nHeight); + } + } + } + } + else { + LogPrintf("UpdateNPListHeights(): Failed to read undo information\n"); + break; + } + pindexSeek = pindexSeek -> pprev; + } + + bool ret; + typedef std::pair > pairType; + BOOST_FOREACH(const pairType &pair, npItem) { + ret = pcoinsTip->SetNPList(pair.first, pair.second); + assert(ret); + } + + if(!UpdateNPList(npItem)) + return false; + return mforkedServiceNPList.empty(); +} + +bool CServiceItemList::GetNPList(std::multiset>> &retset) const { + for(std::map >::const_iterator it=naddresses.begin(); it!=naddresses.end(); it++) + { + retset.insert(std::make_pair(it->first, std::make_tuple(get<0>(it->second), get<1>(it->second), get<2>(it->second)))); + } + return true; +} + +bool CServiceItemList::IsNP(std::string address) { + for (std::map >::const_iterator it = naddresses.begin();it != naddresses.end(); it++) + { + // If address found on np list + if (address == it->first) { + return true; + } + } + return false; +} + diff --git a/src/serviceitemlistdb.h b/src/serviceitemlistdb.h index 702e34d8c..1d601ae1b 100644 --- a/src/serviceitemlistdb.h +++ b/src/serviceitemlistdb.h @@ -10,11 +10,13 @@ typedef std::tuple CServiceUbi; typedef std::tuple CServiceDex; typedef std::tuple CServiceBook; +typedef std::tuple CServiceNP; typedef std::map mapServiceTicketList; typedef std::map mapServiceUbiList; typedef std::map mapServiceDexList; typedef std::map mapServiceBookList; +typedef std::map mapServiceNPList; class CServiceItemList { @@ -23,6 +25,7 @@ class CServiceItemList mapServiceUbiList uaddresses; mapServiceDexList daddresses; mapServiceBookList baddresses; + mapServiceNPList naddresses; bool fForked; std::string TicketAddress(const mapServiceTicketList::iterator &it) const { return it -> first; } @@ -47,12 +50,18 @@ class CServiceItemList std::string ChapterToAddress(const mapServiceBookList::iterator &it) const { return get<1>(it -> second); } std::string ChapterNum(const mapServiceBookList::iterator &it) const { return get<2>(it -> second); } + std::string NPAddress(const mapServiceNPList::iterator &it) const { return it -> first; } + std::string NPAction(const mapServiceNPList::iterator &it) const { return get<0>(it -> second); } + std::string NPToAddress(const mapServiceNPList::iterator &it) const { return get<1>(it -> second); } + std::string NPDescription(const mapServiceNPList::iterator &it) const { return get<2>(it -> second); } + public: friend bool CCoinsViewDB::GetTicketList(CServiceItemList &ticketlist); friend bool CCoinsViewDB::GetUbiList(CServiceItemList &ubilist); friend bool CCoinsViewDB::GetDexList(CServiceItemList &dexlist); friend bool CCoinsViewDB::GetBookList(CServiceItemList &booklist); + friend bool CCoinsViewDB::GetNPList(CServiceItemList &nplist); bool GetTicketList(std::multiset>> &retset) const; bool IsTicket(std::string address); @@ -62,6 +71,8 @@ class CServiceItemList bool IsDex(std::string address); bool GetBookList(std::multiset>> &retset) const; bool IsChapter(std::string address); + bool GetNPList(std::multiset>> &retset) const; + bool IsNP(std::string address); bool SetForked(const bool &fFork); @@ -71,12 +82,14 @@ class CServiceItemList bool UpdateUbiList(const std::map > &map); bool UpdateDexList(const std::map > &map); bool UpdateBookList(const std::map > &map); + bool UpdateNPList(const std::map > &map); bool UpdateTicketListHeights(); bool UpdateUbiListHeights(); bool UpdateDexListHeights(); bool UpdateBookListHeights(); + bool UpdateNPListHeights(); }; -#endif //SMILEYCOIN_SERVICEITEMLISTDB_H \ No newline at end of file +#endif //SMILEYCOIN_SERVICEITEMLISTDB_H diff --git a/src/servicelistdb.cpp b/src/servicelistdb.cpp index 5aa6d28b2..d51297e81 100644 --- a/src/servicelistdb.cpp +++ b/src/servicelistdb.cpp @@ -108,6 +108,8 @@ bool CServiceList::GetServiceAddresses(std::multiset(it->second) == "7") { displayType = "Survey"; + } else if (get<2>(it->second) == "8") { + displayType = "Non-profit Group"; } else { displayType = get<2>(it->second); } @@ -135,6 +137,8 @@ bool CServiceList::GetMyServiceAddresses(std::multiset(it->second) == "7") { displayType = "Survey"; + } else if (get<2>(it->second) == "8") { + displayType = "Non-profit Group"; } else { displayType = get<2>(it->second); } @@ -167,4 +171,4 @@ bool CServiceList::GetTickets(std::string serviceAddress, std::multiset &value) { + // If op_return begins with "DN" (delete np ) + if (get<0>(value) == "DN") { + // Erase the ticket associated with address + batch.Erase(make_pair(DB_SERVICENPLIST, key)); + } else if (get<0>(value) == "NN") { // If op_return begins with NN + batch.Write(make_pair(DB_SERVICENPLIST, key), value); + } +} + void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) { batch.Write(DB_BEST_BLOCK, hash); } @@ -182,6 +194,16 @@ bool CCoinsViewDB::SetBookList(const std::string &key, const std::tuple &value) { + return db.Read(make_pair(DB_SERVICENPLIST, key), value); +} + +bool CCoinsViewDB::SetNPList(const std::string &key, const std::tuple &value) { + CLevelDBBatch batch; + BatchWriteServiceNPList(batch, key, value); + return db.WriteBatch(batch); +} + bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) { return db.Read(make_pair(DB_COINS, txid), coins); } @@ -216,6 +238,7 @@ bool CCoinsViewDB::BatchWrite(const std::map &mapCoins, const std::map> &mapServiceUbiList, const std::map> &mapServiceDexList, const std::map> &mapServiceBookList, + const std::map> &mapServiceNPList, const uint256 &hashBlock) { LogPrint("coindb", "Committing %u changed transactions and %u address balances to coin database...\n",(unsigned int)mapCoins.size(), (unsigned int)mapAddressInfo.size()); @@ -234,6 +257,8 @@ bool CCoinsViewDB::BatchWrite(const std::map &mapCoins, BatchWriteServiceDexList(batch, it->first, it->second); for (std::map>::const_iterator it = mapServiceBookList.begin(); it != mapServiceBookList.end(); it++) BatchWriteServiceBookList(batch, it->first, it->second); + for (std::map>::const_iterator it = mapServiceNPList.begin(); it != mapServiceNPList.end(); it++) + BatchWriteServiceNPList(batch, it->first, it->second); if (hashBlock != uint256(0)) BatchWriteHashBestChain(batch, hashBlock); @@ -461,6 +486,40 @@ bool CCoinsViewDB::GetBookList(CServiceItemList &booklist) { return true; } +bool CCoinsViewDB::GetNPList(CServiceItemList &nplist) { + leveldb::Iterator *pcursor = db.NewIterator(); + CDataStream ssKeySet(SER_DISK, CLIENT_VERSION); + ssKeySet << make_pair(DB_SERVICENPLIST, string("np")); + pcursor->Seek(ssKeySet.str()); + + while (pcursor->Valid()) + { + boost::this_thread::interruption_point(); + try + { + leveldb::Slice slKey = pcursor->key(); + CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION); + std::pair key; + ssKey >> key; + if (key.first == DB_SERVICENPLIST) + { + leveldb::Slice slValue = pcursor->value(); + CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION); + std::tuple npitem; + ssValue >> npitem; + nplist.naddresses.insert(make_pair(key.second, npitem)); + pcursor->Next(); + } else { + break; + } + } catch (std::exception &e) { + return error("%s : Deserialize or I/O error - %s", __func__, e.what()); + } + } + delete pcursor; + + return true; +} CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) { } @@ -637,6 +696,18 @@ bool CBlockTreeDB::ReadServiceBookListFork(bool &fForked) { return true; } +bool CBlockTreeDB::WriteServiceNPListFork(bool fForked) { + if (fForked) + return Write(DB_SERVICENPLIST_FORK_FLAG, '1'); + else + return Erase(DB_SERVICENPLIST_FORK_FLAG); +} + +bool CBlockTreeDB::ReadServiceNPListFork(bool &fForked) { + fForked = Exists(DB_SERVICENPLIST_FORK_FLAG); + return true; +} + bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) { return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0'); } diff --git a/src/txdb.h b/src/txdb.h index 64834b9d8..b43df292c 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -50,6 +50,8 @@ class CCoinsViewDB : public CCoinsView bool SetDexList(const std::string &key, const std::tuple &value); bool GetBookList(const std::string &key, std::tuple &value); bool SetBookList(const std::string &key, const std::tuple &value); + bool GetNPList(const std::string &key, std::tuple &value); + bool SetNPList(const std::string &key, const std::tuple &value); bool HaveCoins(const uint256 &txid); uint256 GetBestBlock(); @@ -60,6 +62,7 @@ class CCoinsViewDB : public CCoinsView const std::map > &mapServiceUbiList, const std::map > &mapServiceDexList, const std::map > &mapServiceBookList, + const std::map > &mapServiceNPList, const uint256 &hashBlock); bool GetStats(CCoinsStats &stats); @@ -69,6 +72,7 @@ class CCoinsViewDB : public CCoinsView bool GetUbiList(CServiceItemList &ubilist); bool GetDexList(CServiceItemList &dexlist); bool GetBookList(CServiceItemList &booklist); + bool GetNPList(CServiceItemList &nplist); }; /** Access to the block database (blocks/index/) */ @@ -102,6 +106,8 @@ class CBlockTreeDB : public CLevelDBWrapper bool ReadServiceDexListFork(bool &fForked); bool WriteServiceBookListFork(bool fForked); bool ReadServiceBookListFork(bool &fForked); + bool WriteServiceNPListFork(bool fForked); + bool ReadServiceNPListFork(bool &fForked); bool WriteFlag(const std::string &name, bool fValue); bool ReadFlag(const std::string &name, bool &fValue); bool LoadBlockIndexGuts();