diff --git a/configure.ac b/configure.ac index ea248f28b..7fa0f437c 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 1) define(_CLIENT_VERSION_REVISION, 8) -define(_CLIENT_VERSION_BUILD, 6) +define(_CLIENT_VERSION_BUILD, 7) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2018) AC_INIT([biblepay Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[https://github.com/biblepaypay/biblepay/issues],[biblepaycore]) diff --git a/src/clientversion.cpp b/src/clientversion.cpp index 5abc3fb85..d840421b8 100644 --- a/src/clientversion.cpp +++ b/src/clientversion.cpp @@ -19,7 +19,7 @@ const std::string CLIENT_NAME("Biblepay Core"); const int BIBLEPAY_VERSION_MAJOR = 1; const int BIBLEPAY_VERSION_MINOR = 1; const int BIBLEPAY_VERSION_REVISION = 8; -const int BIBLEPAY_VERSION_BUILD = 6; +const int BIBLEPAY_VERSION_BUILD = 7; const int BIBLE_VERSION = 1000000 * BIBLEPAY_VERSION_MAJOR diff --git a/src/main.cpp b/src/main.cpp index 9aa1191b0..30ff929aa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1699,8 +1699,33 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C } } } + // BiblePay - If Difficulty is < MIN_POG_DIFF and POG_COUNT > MAX_POG_COUNT, reject the transaction - R ANDREWS - 2/9/2019 + if (chainActive.Tip() != NULL) + { + int nTitheCount = pool.getTitheCount(); + double dPogDiff = GetPOGDifficulty(chainActive.Tip()); + std::string sRecipient = PubKeyToAddress(tx.vout[0].scriptPubKey); + bool bIsTithe = (sRecipient == chainparams.GetConsensus().FoundationAddress); + if (bIsTithe && dPogDiff < LOW_POG_DIFF && nTitheCount > TITHE_OVERFLOW) + { + LogPrintf("AcceptToMemPool::Tithe Overflow Type I; Tithe Rejected; Tithe Count %f, Pog Diff %f ", nTitheCount, dPogDiff); + return false; + } + else if (bIsTithe && nTitheCount > (TITHE_OVERFLOW * 2)) + { + LogPrintf("AcceptToMemPool::Tithe Overflow Type II; Tithe Rejected; Tithe Count %f, Pog Diff %f ", nTitheCount, dPogDiff); + return false; + } + else if (bIsTithe && dPogDiff < LOW_POG_DIFF && chainActive.Height() < POG_V2_CUTOVER_HEIGHT_PROD && nTitheCount > (TITHE_OVERFLOW / 15)) + { + LogPrintf("AcceptToMemPool::Tithe Overflow Type III; Tithe Rejected; Tithe Count %f, Pog Diff %f ", nTitheCount, dPogDiff); + return false; + } + LogPrintf("Tithe Count %f, Diff %f ",(double)nTitheCount, dPogDiff); + } + // If we aren't going to actually accept it but just were verifying it, we are fine already - if(fDryRun) return true; + if (fDryRun) return true; // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. diff --git a/src/main.h b/src/main.h index 9954b010f..855b1bdb8 100644 --- a/src/main.h +++ b/src/main.h @@ -87,9 +87,13 @@ static const int F14000_CUTOVER_HEIGHT_PROD = 77000; // October 14th, 2018 static const int F14000_CUTOVER_HEIGHT_TESTNET = 54300; // Sep. 1, 2018 static const int FPOG_CUTOVER_HEIGHT_TESTNET = 95945; // Dec. 23rd, 2018 static const int FPOG_CUTOVER_HEIGHT_PROD = 100001; // Feb 7th, 2019 (100,001) -static const int PODC_LAST_BLOCK_PROD = 106150; // March 8th, 2019 (106,150) +static const int PODC_LAST_BLOCK_PROD = 107000; // March 13th, 2019 static const int PODC_LAST_BLOCK_TESTNET = 126150; +static const int POG_V2_CUTOVER_HEIGHT_PROD = 102025; +static const int LOW_POG_DIFF = 5000; +static const int TITHE_OVERFLOW = 75; static const int MINIMUM_EMAIL_LENGTH = 5; // 3 character domain + . + 1 character name + /** Default for -maxorphantx, maximum number of orphan transactions kept in memory */ static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100; /** Default for -limitancestorcount, max number of in-mempool ancestors */ diff --git a/src/miner.cpp b/src/miner.cpp index 679afd8b9..0fa99a1f2 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -809,7 +809,7 @@ void static BibleMiner(const CChainParams& chainparams, int iThreadID, int iFeat // POG - R ANDREWS - 12/6/2018 - Once every 4 hours, tithe if profitable and possible int64_t nPOGTitheAge = GetAdjustedTime() - nLastPOGTithe; - if (fPOGEnabled && nPOGTitheFrequency > 120 && iThreadID == 0 && (nPOGTitheAge > (nPOGTitheFrequency))) + if (fPOGEnabled && nPOGTitheFrequency > 119 && iThreadID == 0 && (nPOGTitheAge > (nPOGTitheFrequency))) { nLastPOGTithe = GetAdjustedTime(); CAmount nTitheAmount = SelectCoinsForTithing(chainActive.Tip()); diff --git a/src/qt/businessobjectlist.cpp b/src/qt/businessobjectlist.cpp index 77786ec67..11606704d 100644 --- a/src/qt/businessobjectlist.cpp +++ b/src/qt/businessobjectlist.cpp @@ -95,6 +95,8 @@ void BusinessObjectList::createUI(const QStringList &headers, const QString &pSt { ui->tableWidget->setShowGrid(true); ui->tableWidget->setRowCount(0); + ui->tableWidget->setSortingEnabled(false); + ui->tableWidget->setSelectionMode(QAbstractItemView::SingleSelection); ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows); @@ -134,6 +136,7 @@ void BusinessObjectList::createUI(const QStringList &headers, const QString &pSt for(int j = 0; j < cols; j++) { QTableWidgetItem* q = new QTableWidgetItem(pMatrix[i][j]); + if (j == iAmountCol) q = new QTableWidgetItem(cdbl(GUIUtil::FROMQS(pMatrix[i][j]), 2)); ui->tableWidget->setItem(i, j, q); } if (bHighlighted) @@ -150,6 +153,9 @@ void BusinessObjectList::createUI(const QStringList &headers, const QString &pSt if (ObjectType == "pog_leaderboard") { + // Sort by ShareWeight descending + ui->tableWidget->sortByColumn(5, Qt::DescendingOrder); + ui->tableWidget->setSortingEnabled(true); std::string sXML = GUIUtil::FROMQS(pStr); addFooterRow(rows, iFooterRow, "Difficulty:", ExtractXML(sXML, "","")); addFooterRow(rows, iFooterRow, "My Tithes:", ExtractXML(sXML, "","")); @@ -265,7 +271,13 @@ void BusinessObjectList::slotReviewLetter() { QMessageBox msgBox; std::string id = GUIUtil::FROMQS(ui->tableWidget->item(row, 0)->text()); - WriteOrphan *dlg = new WriteOrphan(this, "REVIEW", "", id); + // If we wrote this letter, allow edit: + std::string sReceivingAddress = DefaultRecAddress(BUSINESS_OBJECTS); + int iCol = GetUrlColumn("receiving_address"); + std::string sWriterAddr = GUIUtil::FROMQS(ui->tableWidget->item(row, iCol)->text()); + bool bOwned = (sWriterAddr == sReceivingAddress && !sWriterAddr.empty()); + std::string sMode = bOwned ? "EDIT" : "REVIEW"; + WriteOrphan *dlg = new WriteOrphan(this, sMode, "", id); dlg->show(); } } diff --git a/src/qt/masternodelist.cpp b/src/qt/masternodelist.cpp index 0d54f9dad..776430a26 100644 --- a/src/qt/masternodelist.cpp +++ b/src/qt/masternodelist.cpp @@ -173,6 +173,8 @@ void MasternodeList::StartAll(std::string strCommand) void MasternodeList::StartOne() { + return; + int nCountSuccessful = 0; int nCountFailed = 0; std::string strFailedHtml; diff --git a/src/qt/writeorphan.cpp b/src/qt/writeorphan.cpp index f103dc079..a3d3a1c6b 100644 --- a/src/qt/writeorphan.cpp +++ b/src/qt/writeorphan.cpp @@ -19,7 +19,17 @@ #include #include - +std::string GetLetterId(std::string sObjId) +{ + std::vector vFields = Split(sObjId.c_str(), "-"); + if (vFields.size() > 1) + { + std::string sID = vFields[1]; + return sID; + } + return sObjId; +} + WriteOrphan::WriteOrphan(QWidget *parent, std::string xMode, std::string xOrphanID, std::string xLetterID) : QDialog(parent),ui(new Ui::WriteOrphan) { ui->setupUi(this); @@ -40,7 +50,7 @@ WriteOrphan::WriteOrphan(QWidget *parent, std::string xMode, std::string xOrphan else { // The letter ID is the IPFS letter ID - sObjectID = xLetterID; + sObjectID = GetLetterId(xLetterID); } // The Attachment directory is the hash of the letterID sDir = GetSANDirectory2() + RetrieveMd5(sObjectID) + "/"; @@ -51,6 +61,12 @@ WriteOrphan::WriteOrphan(QWidget *parent, std::string xMode, std::string xOrphan ui->btnSave->setEnabled(false); ui->btnAttachImage->setEnabled(false); } + else if (sMode == "EDIT") + { + Load(); + ui->btnSave->setEnabled(true); + ui->btnAttachImage->setEnabled(true); + } PopulateAttachedPics(); connect(ui->btnAttachImage, SIGNAL(clicked()), this, SLOT(AttachImage())); connect(ui->btnSave, SIGNAL(clicked()), this, SLOT(SaveRecord())); @@ -60,7 +76,7 @@ WriteOrphan::WriteOrphan(QWidget *parent, std::string xMode, std::string xOrphan void WriteOrphan::SaveRecord() { std::string sTXID = Save(); - std::string sNarr = (sTXID.empty()) ? "Unable to save record. (Ensure wallet is unlocked and retry, next check IPFS configuration.)" : "Successfully saved letter " + sTXID + ". Thank you for writing to BiblePay Orphans!"; + std::string sNarr = (sTXID.empty()) ? "Unable to save record. (Ensure wallet is unlocked and retry, next check IPFS configuration.)" : "Successfully saved letter " + sObjectID + "-" + sTXID + ". Thank you for writing to BiblePay Orphans!"; QMessageBox::warning(this, tr("Save Letter"), GUIUtil::TOQS(sNarr)); } @@ -147,9 +163,7 @@ void WriteOrphan::Load() if (nTries > MAX_RETRIES_NETWORK_FAILURE) return; // In case of network failure, this occurs if the page links cannot be downloaded std::string sError; UniValue aBO(UniValue::VOBJ); - std::vector vFields = Split(sObjectID.c_str(), "-"); - - aBO = GetBusinessObject("LETTER", vFields[1], sError); + aBO = GetBusinessObject("LETTER", GetLetterId(sObjectID), sError); sOrphanID = aBO["orphanid"].getValStr(); std::string sBody = aBO["body"].getValStr(); std::string sAdded = aBO["added"].getValStr(); @@ -182,6 +196,7 @@ std::string WriteOrphan::Save() UniValue oBO(UniValue::VOBJ); oBO.push_back(Pair("objecttype", "letter")); oBO.push_back(Pair("primarykey", "letter")); + // Allow re-saving the object using the original object ID if the user has permissions oBO.push_back(Pair("secondarykey", sObjectID)); oBO.push_back(Pair("added", RoundToString(GetAdjustedTime(), 0))); oBO.push_back(Pair("deleted", "0")); diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index b1a94d130..86219b0a2 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -3188,6 +3188,10 @@ UniValue exec(const UniValue& params, bool fHelp) results.push_back(Pair("vout", sRecipient)); } } + int nTitheCount = mempool.getTitheCount(); + double dPogDiff = GetPOGDifficulty(chainActive.Tip()); + results.push_back(Pair("tithe_count", nTitheCount)); + results.push_back(Pair("pog_difficulty", dPogDiff)); } else if (sItem == "chat1") { diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index 5cb3dc44d..b1fa75cfc 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -103,7 +103,7 @@ UniValue getinfo(const UniValue& params, bool fHelp) obj.push_back(Pair("timeoffset", GetTimeOffset())); obj.push_back(Pair("connections", (int)vNodes.size())); obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string()))); - obj.push_back(Pair("difficulty", (double)GetDifficulty())); + obj.push_back(Pair("difficulty", (double)GetDifficultyN(NULL, 10))); obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); #ifdef ENABLE_WALLET if (pwalletMain) { diff --git a/src/rpcpog.cpp b/src/rpcpog.cpp index c8feda2fa..d9d0c4ddc 100644 --- a/src/rpcpog.cpp +++ b/src/rpcpog.cpp @@ -172,6 +172,7 @@ TitheDifficultyParams GetTitheParams(const CBlockIndex* pindex) td.min_coin_amount = 0; td.max_tithe_amount = 0; if (pindex == NULL || pindex->nHeight == 0) return td; + if (fProd && pindex->nHeight > POG_V2_CUTOVER_HEIGHT_PROD) return GetTitheParams2(pindex); CAmount nTitheCap = GetTitheCap(pindex); if (nTitheCap < 1) return td; double nQLevel = (((double)pindex->n24HourTithes/COIN) / ((double)nTitheCap/COIN)); @@ -181,6 +182,30 @@ TitheDifficultyParams GetTitheParams(const CBlockIndex* pindex) return td; } +TitheDifficultyParams GetTitheParams2(const CBlockIndex* pindex) +{ + // V2.0 - R ANDREWS - BIBLEPAY - FEB 9th, 2019 + // V1.0 was subject to catastrophic cycling (due to a high max_tithe_amount accomodating too few participants and due to having no coin age requirement at the lowest diff - and due to the mempool overflow rejection business logic rule not being in place in prod) + // After the cutover height, we use V2.0 in prod + + // Tithe Parameter Ranges: + // min_coin_age : .25 - 60 (days) + // min_coin_amount : 1 - 25000 + // max_tithe_amount: 10 - .25 (descending) + TitheDifficultyParams td; + td.min_coin_age = 99999; + td.min_coin_amount = 0; + td.max_tithe_amount = 0; + if (pindex == NULL || pindex->nHeight == 0) return td; + CAmount nTitheCap = GetTitheCap(pindex); + if (nTitheCap < 1) return td; + double nQLevel = (((double)pindex->n24HourTithes/COIN) / ((double)nTitheCap/COIN)); + td.min_coin_age = R2X(Quantize(.25, 60, nQLevel)); + td.min_coin_amount = R2X(Quantize(1, 25000, nQLevel)) * COIN; + td.max_tithe_amount = R2X(Quantize(10, .25, nQLevel)) * COIN; // Descending tithe amount + return td; +} + CAmount SelectCoinsForTithing(const CBlockIndex* pindex) { TitheDifficultyParams tdp = GetTitheParams(pindex); @@ -784,6 +809,7 @@ std::string StoreBusinessObjectWithPK(UniValue& oBusinessObject, std::string& sE double dStorageFee = 1; std::string sTxId = ""; sTxId = SendBusinessObject(sOT, sPK + sSecondaryKey, sIPFSHash, dStorageFee, sSignKey, true, sError); + WriteCache(sPK, sSecondaryKey, sIPFSHash, GetAdjustedTime()); return sTxId; } return ""; @@ -1697,7 +1723,6 @@ std::string SendBusinessObject(std::string sType, std::string sPrimaryKey, std:: if (bSigned) { sMessageSig = "" + sSignature + ""; - WriteCache(sType, sSignKey, sValue, GetAdjustedTime()); } } std::string s1 = sMessageType + sMessageKey + sMessageValue + sNonce + sBOSignKey + sMessageSig; @@ -1710,8 +1735,6 @@ std::string SendBusinessObject(std::string sType, std::string sPrimaryKey, std:: return wtx.GetHash().GetHex().c_str(); } - - int GetSignalInt(std::string sLocalSignal) { boost::to_upper(sLocalSignal); diff --git a/src/rpcpog.h b/src/rpcpog.h index cb62cae99..46f04a2ad 100644 --- a/src/rpcpog.h +++ b/src/rpcpog.h @@ -105,6 +105,7 @@ struct TitheDifficultyParams }; TitheDifficultyParams GetTitheParams(const CBlockIndex* pindex); +TitheDifficultyParams GetTitheParams2(const CBlockIndex* pindex); std::vector ReadBytesAll(char const* filename); std::string VectToString(std::vector v); CAmount StringToAmount(std::string sValue); diff --git a/src/txmempool.cpp b/src/txmempool.cpp index abfc56a82..f2662702d 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -16,6 +16,7 @@ #include "utilmoneystr.h" #include "utiltime.h" #include "version.h" +#include "chainparams.h" using namespace std; @@ -865,6 +866,31 @@ void CTxMemPool::queryHashes(vector& vtxid) vtxid.push_back(mi->GetTx().GetHash()); } +int CTxMemPool::getTitheCount() +{ + std::vector vtxid; + queryHashes(vtxid); + int i = 0; + BOOST_FOREACH(uint256& hash, vtxid) + { + CTransaction tx; + bool fInMemPool = mempool.lookup(hash, tx); + if (fInMemPool) + { + for (unsigned int z = 0; z < tx.vout.size(); z++) + { + std::string sRecip = PubKeyToAddress(tx.vout[z].scriptPubKey); + if (sRecip == Params().GetConsensus().FoundationAddress) + { + i++; + break; + } + } + } + } + return i; +} + bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const { LOCK(cs); diff --git a/src/txmempool.h b/src/txmempool.h index 030012b76..3a47d516a 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -8,13 +8,13 @@ #include #include - #include "addressindex.h" #include "spentindex.h" #include "amount.h" #include "coins.h" #include "primitives/transaction.h" #include "sync.h" +#include "chainparams.h" #undef foreach #include "boost/multi_index_container.hpp" @@ -482,6 +482,8 @@ class CTxMemPool void clear(); void _clear(); //lock free void queryHashes(std::vector& vtxid); + int getTitheCount(); + void pruneSpent(const uint256& hash, CCoins &coins); unsigned int GetTransactionsUpdated() const; void AddTransactionsUpdated(unsigned int n);