diff --git a/configure.ac b/configure.ac index 1e22dca7a..64e4ecb41 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 0) define(_CLIENT_VERSION_MINOR, 11) define(_CLIENT_VERSION_REVISION, 0) -define(_CLIENT_VERSION_BUILD, 3) +define(_CLIENT_VERSION_BUILD, 4) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2015) AC_INIT([Darkcoin Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[info@darkcoin.io],[darkcoin]) diff --git a/src/activemasternode.cpp b/src/activemasternode.cpp index f008e8f36..ef047a0f2 100644 --- a/src/activemasternode.cpp +++ b/src/activemasternode.cpp @@ -302,8 +302,7 @@ bool CActiveMasternode::GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secr if(!strTxHash.empty()) { // Let's find it uint256 txHash(strTxHash); - int outputIndex = 0; - outputIndex = boost::lexical_cast(outputIndex); + int outputIndex = boost::lexical_cast(strOutputIndex); bool found = false; BOOST_FOREACH(COutput& out, possibleCoins) { if(out.tx->GetHash() == txHash && out.i == outputIndex) diff --git a/src/clientversion.h b/src/clientversion.h index b355f6c05..bd10b9c50 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -13,7 +13,7 @@ #define CLIENT_VERSION_MAJOR 0 #define CLIENT_VERSION_MINOR 11 #define CLIENT_VERSION_REVISION 0 -#define CLIENT_VERSION_BUILD 3 +#define CLIENT_VERSION_BUILD 4 diff --git a/src/core.h b/src/core.h index 8124b39a5..30d9fc9d4 100644 --- a/src/core.h +++ b/src/core.h @@ -12,7 +12,7 @@ #include -#define START_MASTERNODE_PAYMENTS_TESTNET 1403568776 //Tue, 24 Jun 2014 00:12:56 GMT +#define START_MASTERNODE_PAYMENTS_TESTNET 1420837558 //Fri, 09 Jan 2015 21:05:58 GMT #define START_MASTERNODE_PAYMENTS 1403728576 //Wed, 25 Jun 2014 20:36:16 GMT static const int64_t DARKSEND_COLLATERAL = (0.1*COIN); @@ -181,7 +181,7 @@ public: // to spend something, then we consider it dust. // A typical txout is 34 bytes big, and will // need a CTxIn of at least 148 bytes to spend, - // so dust is a txout less than 546 satoshis + // so dust is a txout less than 546 satoshis // with default nMinRelayTxFee. return ((nValue*1000)/(3*((int)GetSerializeSize(SER_DISK,0)+148)) < nMinRelayTxFee); } diff --git a/src/darksend.cpp b/src/darksend.cpp index b770299e7..f488d36f3 100644 --- a/src/darksend.cpp +++ b/src/darksend.cpp @@ -435,6 +435,7 @@ int GetInputDarksendRounds(CTxIn in, int rounds) void CDarkSendPool::Reset(){ cachedLastSuccess = 0; vecMasternodesUsed.clear(); + UnlockCoins(); SetNull(); } @@ -756,6 +757,15 @@ void CDarkSendPool::ChargeRandomFees(){ BOOST_FOREACH(const CTransaction& txCollateral, vecSessionCollateral) { int r = rand()%1000; + /* + Collateral Fee Charges: + + Being that DarkSend has "no fees" we need to have some kind of cost associated + with using it to stop abuse. Otherwise it could serve as an attack vector and + allow endless transaction that would bloat Darkcoin and make it unusable. To + stop these kinds of attacks 1 in 50 successful transactions are charged. This + adds up to a cost of 0.002DRK per transaction on average. + */ if(r <= 20) { LogPrintf("CDarkSendPool::ChargeRandomFees -- charging random fees. %u\n", i); @@ -1519,7 +1529,7 @@ bool CDarkSendPool::DoAutomaticDenominating(bool fDryRun, bool ready) if(sessionTotalValue > maxAmount*COIN) sessionTotalValue = maxAmount*COIN; double fDarkcoinSubmitted = (sessionTotalValue / CENT); - LogPrintf("Submiting Darksend for %f DRK CENT\n", fDarkcoinSubmitted); + LogPrintf("Submitting Darksend for %f DRK CENT\n", fDarkcoinSubmitted); if(pwalletMain->GetDenominatedBalance(true, true) > 0){ //get denominated unconfirmed inputs LogPrintf("DoAutomaticDenominating -- Found unconfirmed denominated outputs, will wait till they confirm to continue.\n"); @@ -1666,6 +1676,8 @@ bool CDarkSendPool::DoAutomaticDenominating(bool fDryRun, bool ready) if(!ready) return true; if(sessionDenom == 0) return true; + + return false; } diff --git a/src/main.cpp b/src/main.cpp index 7808c61ce..4e083ceb4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1052,10 +1052,6 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState &state, const CTransact CCoinsViewMemPool viewMemPool(*pcoinsTip, pool); view.SetBackend(viewMemPool); - // do we already have it? - if (view.HaveCoins(hash)) - return false; - // do all inputs exist? // Note that this does not check for the presence of actual outputs (see the next check for that), // only helps filling in pfMissingInputs (to determine missing vs spent). @@ -2918,7 +2914,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo CBitcoinAddress address2(address1); LogPrintf("CheckBlock() : Couldn't find masternode payment(%d|%d) or payee(%d|%s) nHeight %d. \n", foundPaymentAmount, masternodePaymentAmount, foundPayee, address2.ToString().c_str(), chainActive.Tip()->nHeight+1); - if(!TestNet() && !RegTest()) return state.DoS(100, error("CheckBlock() : Couldn't find masternode payment or payee")); + if(!RegTest()) return state.DoS(100, error("CheckBlock() : Couldn't find masternode payment or payee")); } } } else { diff --git a/src/masternodeconfig.cpp b/src/masternodeconfig.cpp index 5dbfdf1c1..12afcce2f 100644 --- a/src/masternodeconfig.cpp +++ b/src/masternodeconfig.cpp @@ -1,3 +1,5 @@ + +#include "net.h" #include "masternodeconfig.h" #include "util.h" @@ -26,6 +28,13 @@ bool CMasternodeConfig::read(boost::filesystem::path path, std::string& strErr) streamConfig.close(); return false; } + + if(CService(ip).GetPort() != 19999 && CService(ip).GetPort() != 9999) { + strErr = "Invalid port (must be 9999 for mainnet or 19999 for testnet) detected in masternode.conf: " + line; + streamConfig.close(); + return false; + } + add(alias, ip, privKey, txHash, outputIndex); } diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 633cb9f3b..1dc012fdc 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -261,6 +261,13 @@ void OverviewPage::updateDarksendProgress(){ int64_t nValueMin = 0.01*COIN; int64_t nValueIn = 0; + if(pwalletMain->GetDenominatedBalance(true, true) > 0){ //get denominated unconfirmed inputs + QString s("Found unconfirmed denominated outputs, will wait till they confirm to recalculate."); + ui->darksendProgress->setToolTip(s); + return; + } + + // Calculate total mixable funds if (!pwalletMain->SelectCoinsDark(nValueMin, 999999*COIN, vCoins, nValueIn, -2, 10)) { ui->darksendProgress->setValue(0); @@ -270,14 +277,17 @@ void OverviewPage::updateDarksendProgress(){ } double nTotalValue = pwalletMain->GetTotalValue(vCoins)/CENT; - //Get average rounds of inputs - double a = (double)pwalletMain->GetAverageAnonymizedRounds() / (double)nDarksendRounds; //Get the anon threshold double max = nAnonymizeDarkcoinAmount*100; //If it's more than the wallet amount, limit to that. if(max > (double)nTotalValue) max = (double)nTotalValue; //denominated balance / anon threshold -- the percentage that we've completed double b = ((double)(pwalletMain->GetDenominatedBalance()/CENT) / max); + if(b > 1) b = 1; + + //Get average rounds of inputs + double a = (double)pwalletMain->GetAverageAnonymizedRounds() / (double)nDarksendRounds; + if(a > 1) a = 1; double val = a*b*100; if(val < 0) val = 0; diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 645928585..4773224c5 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -85,6 +85,23 @@ QList TransactionRecord::decomposeTransaction(const CWallet * if (fAllFromMe && fAllToMe) { + + for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) + { + const CTxOut& txout = wtx.vout[nOut]; + TransactionRecord sub(hash, nTime); + sub.idx = parts.size(); + + if(txout.nValue == (DARKSEND_COLLATERAL*2)+DARKSEND_FEE || + txout.nValue == (DARKSEND_COLLATERAL*2)+DARKSEND_FEE || + txout.nValue == (DARKSEND_COLLATERAL*3)+DARKSEND_FEE || + txout.nValue == (DARKSEND_COLLATERAL*4)+DARKSEND_FEE || + txout.nValue == (DARKSEND_COLLATERAL*5)+DARKSEND_FEE + ) { + sub.type = TransactionRecord::DarksendSplitUpLarge; + } + } + // Payment to self int64_t nChange = wtx.GetChange(); @@ -125,6 +142,17 @@ QList TransactionRecord::decomposeTransaction(const CWallet * sub.address = mapValue["to"]; } + if(wtx.IsDenominated()){ + sub.type = TransactionRecord::Darksent; + } + + if(txout.nValue == DARKSEND_COLLATERAL){ + sub.type = TransactionRecord::DarksendCollateralPayment; + } + if(txout.nValue == DARKSEND_COLLATERAL*5){ + sub.type = TransactionRecord::DarksendSplitUpLarge; + } + int64_t nValue = txout.nValue; /* Add fee to first output */ if (nTxFee > 0) @@ -142,7 +170,18 @@ QList TransactionRecord::decomposeTransaction(const CWallet * // // Mixed debit transaction, can't break down payees // - parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0)); + bool isDarksent = false; + + for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) + { + const CTxOut& txout = wtx.vout[nOut]; + + BOOST_FOREACH(int64_t d, darkSendDenominations) + if(txout.nValue == d) + isDarksent = true; + } + + parts.append(TransactionRecord(hash, nTime, isDarksent ? TransactionRecord::DarksendDenominate : TransactionRecord::Other, "", nNet, 0)); } } diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h index af6fd403b..e7d008dcf 100644 --- a/src/qt/transactionrecord.h +++ b/src/qt/transactionrecord.h @@ -75,7 +75,12 @@ public: SendToOther, RecvWithAddress, RecvFromOther, - SendToSelf + SendToSelf, + RecvWithDarksend, + DarksendDenominate, + DarksendCollateralPayment, + DarksendSplitUpLarge, + Darksent }; /** Number of confirmation recommended for accepting a transaction */ diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 8cf2b0a1b..dff083c1e 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -356,6 +356,8 @@ QString TransactionTableModel::formatTxType(const TransactionRecord *wtx) const return tr("Received with"); case TransactionRecord::RecvFromOther: return tr("Received from"); + case TransactionRecord::RecvWithDarksend: + return tr("Received via Darksend"); case TransactionRecord::SendToAddress: case TransactionRecord::SendToOther: return tr("Sent to"); @@ -363,6 +365,16 @@ QString TransactionTableModel::formatTxType(const TransactionRecord *wtx) const return tr("Payment to yourself"); case TransactionRecord::Generated: return tr("Mined"); + + case TransactionRecord::DarksendDenominate: + return tr("Darksend Denominate"); + case TransactionRecord::DarksendCollateralPayment: + return tr("Darksend Collateral Payment"); + case TransactionRecord::DarksendSplitUpLarge: + return tr("Darksend Split Up Large Inputs"); + case TransactionRecord::Darksent: + return tr("Darksent"); + default: return QString(); } @@ -374,6 +386,7 @@ QVariant TransactionTableModel::txAddressDecoration(const TransactionRecord *wtx { case TransactionRecord::Generated: return QIcon(":/icons/tx_mined"); + case TransactionRecord::RecvWithDarksend: case TransactionRecord::RecvWithAddress: case TransactionRecord::RecvFromOther: return QIcon(":/icons/tx_input"); @@ -393,8 +406,10 @@ QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, b case TransactionRecord::RecvFromOther: return QString::fromStdString(wtx->address); case TransactionRecord::RecvWithAddress: + case TransactionRecord::RecvWithDarksend: case TransactionRecord::SendToAddress: case TransactionRecord::Generated: + case TransactionRecord::Darksent: return lookupAddress(wtx->address, tooltip); case TransactionRecord::SendToOther: return QString::fromStdString(wtx->address); diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index d4d29416c..46316773b 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -78,6 +78,8 @@ TransactionView::TransactionView(QWidget *parent) : TransactionFilterProxy::TYPE(TransactionRecord::RecvFromOther)); typeWidget->addItem(tr("Sent to"), TransactionFilterProxy::TYPE(TransactionRecord::SendToAddress) | TransactionFilterProxy::TYPE(TransactionRecord::SendToOther)); + typeWidget->addItem(tr("Darksent"), TransactionFilterProxy::TYPE(TransactionRecord::Darksent)); + typeWidget->addItem(tr("Darksend Denominate"), TransactionFilterProxy::TYPE(TransactionRecord::DarksendDenominate)); typeWidget->addItem(tr("To yourself"), TransactionFilterProxy::TYPE(TransactionRecord::SendToSelf)); typeWidget->addItem(tr("Mined"), TransactionFilterProxy::TYPE(TransactionRecord::Generated)); typeWidget->addItem(tr("Other"), TransactionFilterProxy::TYPE(TransactionRecord::Other)); diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 3e276d195..bbbbdf1ea 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -5,6 +5,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "rpcserver.h" +#include "base58.h" #include "chainparams.h" #include "init.h" #include "net.h" @@ -456,6 +457,9 @@ Value getblocktemplate(const Array& params, bool fHelp) " \"curtime\" : ttt, (numeric) current timestamp in seconds since epoch (Jan 1 1970 GMT)\n" " \"bits\" : \"xxx\", (string) compressed target of next block\n" " \"height\" : n (numeric) The height of the next block\n" + " \"payee\" : required payee\n" + " \"payee_amount\" : required amount to pay\n" + " \"votes\" : show vote candidates for this block\n" "}\n" "\nExamples:\n" @@ -570,6 +574,8 @@ Value getblocktemplate(const Array& params, bool fHelp) aMutable.push_back("prevblock"); } + Array aVotes; + Object result; result.push_back(Pair("version", pblock->nVersion)); result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); @@ -585,6 +591,31 @@ Value getblocktemplate(const Array& params, bool fHelp) result.push_back(Pair("curtime", (int64_t)pblock->nTime)); result.push_back(Pair("bits", HexBits(pblock->nBits))); result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1))); + result.push_back(Pair("votes", aVotes)); + + + if(pblock->payee != CScript()){ + CTxDestination address1; + ExtractDestination(pblock->payee, address1); + CBitcoinAddress address2(address1); + result.push_back(Pair("payee", address2.ToString().c_str())); + result.push_back(Pair("payee_amount", (int64_t)GetMasternodePayment(pindexPrev->nHeight+1, pblock->vtx[0].GetValueOut()))); + } else { + result.push_back(Pair("payee", "")); + result.push_back(Pair("payee_amount", "")); + } + + bool MasternodePayments = false; + + if(TestNet()){ + if(pblock->nTime > START_MASTERNODE_PAYMENTS_TESTNET) MasternodePayments = true; + } else { + if(pblock->nTime > START_MASTERNODE_PAYMENTS) MasternodePayments = true; + } + + + result.push_back(Pair("masternode_payments", MasternodePayments)); + result.push_back(Pair("enforce_masternode_payments", true)); return result; } diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index afec75c97..b8b5fb8dd 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -39,6 +39,7 @@ Value getinfo(const Array& params, bool fHelp) " \"protocolversion\": xxxxx, (numeric) the protocol version\n" " \"walletversion\": xxxxx, (numeric) the wallet version\n" " \"balance\": xxxxxxx, (numeric) the total darkcoin balance of the wallet\n" + " \"darksend_balance\": xxxxxx, (numeric) the anonymized darkcoin balance of the wallet\n" " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n" " \"timeoffset\": xxxxx, (numeric) the time offset\n" " \"connections\": xxxxx, (numeric) the number of connections\n" @@ -67,6 +68,7 @@ Value getinfo(const Array& params, bool fHelp) if (pwalletMain) { obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); + obj.push_back(Pair("darksend_balance", ValueFromAmount(pwalletMain->GetAnonymizedBalance()))); } #endif obj.push_back(Pair("blocks", (int)chainActive.Height())); diff --git a/src/wallet.cpp b/src/wallet.cpp index 7ff8b0046..1b57485d8 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1068,6 +1068,7 @@ double CWallet::GetAverageAnonymizedRounds() const for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; + for (unsigned int i = 0; i < pcoin->vout.size(); i++) { COutput out = COutput(pcoin, i, pcoin->GetDepthInMainChain()); @@ -1096,26 +1097,27 @@ int64_t CWallet::GetDenominatedBalance(bool onlyDenom, bool onlyUnconfirmed) con { const CWalletTx* pcoin = &(*it).second; - bool isDenom = false; for (unsigned int i = 0; i < pcoin->vout.size(); i++) - BOOST_FOREACH(int64_t d, darkSendDenominations) - if(pcoin->vout[i].nValue == d) - isDenom = true; + { + COutput out = COutput(pcoin, i, pcoin->GetDepthInMainChain()); + CTxIn vin = CTxIn(out.tx->GetHash(), out.i); - if(onlyUnconfirmed){ - if (!pcoin->IsTrusted()){ - if(onlyDenom == isDenom){ - nTotal += pcoin->GetAvailableCredit(); - } - } - } else if (pcoin->IsTrusted()) { - if(onlyDenom == isDenom) { - nTotal += pcoin->GetAvailableCredit(); - } + bool unconfirmed = (!IsFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0)); + + if(IsSpent(out.tx->GetHash(), i)) continue; + if(!IsMine(pcoin->vout[i])) continue; + if(onlyUnconfirmed != unconfirmed) continue; + + int rounds = GetInputDarksendRounds(vin); + if(onlyDenom != (rounds>=0)) continue; + + nTotal += pcoin->vout[i].nValue; } } } + + return nTotal; }