mirror of
https://github.com/dashpay/dash.git
synced 2024-12-27 13:03:17 +01:00
merge downstream 0.11.1
This commit is contained in:
commit
78d47c04fe
@ -3,7 +3,7 @@ AC_PREREQ([2.60])
|
|||||||
define(_CLIENT_VERSION_MAJOR, 0)
|
define(_CLIENT_VERSION_MAJOR, 0)
|
||||||
define(_CLIENT_VERSION_MINOR, 11)
|
define(_CLIENT_VERSION_MINOR, 11)
|
||||||
define(_CLIENT_VERSION_REVISION, 1)
|
define(_CLIENT_VERSION_REVISION, 1)
|
||||||
define(_CLIENT_VERSION_BUILD, 7)
|
define(_CLIENT_VERSION_BUILD, 8)
|
||||||
define(_CLIENT_VERSION_IS_RELEASE, true)
|
define(_CLIENT_VERSION_IS_RELEASE, true)
|
||||||
define(_COPYRIGHT_YEAR, 2015)
|
define(_COPYRIGHT_YEAR, 2015)
|
||||||
AC_INIT([Darkcoin Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[info@darkcoin.io],[darkcoin])
|
AC_INIT([Darkcoin Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[info@darkcoin.io],[darkcoin])
|
||||||
|
@ -16,6 +16,8 @@ and a new version of enforcement compatible with the newer Bitcoin architechure.
|
|||||||
- Added --instantxdepth, which will show X confirmations when a transaction lock is present
|
- Added --instantxdepth, which will show X confirmations when a transaction lock is present
|
||||||
- fix coin control crash https://github.com/bitcoin/bitcoin/pull/5700
|
- fix coin control crash https://github.com/bitcoin/bitcoin/pull/5700
|
||||||
- always get only confirmed coins by AvailableCoins for every DS relative action
|
- always get only confirmed coins by AvailableCoins for every DS relative action
|
||||||
|
- New languages supported Portuguese, German, Russian, Polish, Spanish, Vietnamese, French,
|
||||||
|
Italian, Catalan, Chinese, Danish, Finnish, Swedish, Czech, Turkish and Bavarian (and many more)
|
||||||
|
|
||||||
|
|
||||||
Thanks to who contributed to this release, at least:
|
Thanks to who contributed to this release, at least:
|
||||||
@ -23,6 +25,7 @@ Thanks to who contributed to this release, at least:
|
|||||||
- Vertoe
|
- Vertoe
|
||||||
- Udjin
|
- Udjin
|
||||||
- Holger Schinzel
|
- Holger Schinzel
|
||||||
|
- Raze
|
||||||
- Mario Müller
|
- Mario Müller
|
||||||
- Crowning
|
- Crowning
|
||||||
- Alexandre Devilliers
|
- Alexandre Devilliers
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
#define CLIENT_VERSION_MAJOR 0
|
#define CLIENT_VERSION_MAJOR 0
|
||||||
#define CLIENT_VERSION_MINOR 11
|
#define CLIENT_VERSION_MINOR 11
|
||||||
#define CLIENT_VERSION_REVISION 1
|
#define CLIENT_VERSION_REVISION 1
|
||||||
#define CLIENT_VERSION_BUILD 7
|
#define CLIENT_VERSION_BUILD 8
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1364,8 +1364,6 @@ void CDarkSendPool::NewBlock()
|
|||||||
|
|
||||||
darkSendPool.CheckTimeout();
|
darkSendPool.CheckTimeout();
|
||||||
|
|
||||||
masternodePayments.ProcessBlock(chainActive.Tip()->nHeight+10);
|
|
||||||
|
|
||||||
if(!fEnableDarksend) return;
|
if(!fEnableDarksend) return;
|
||||||
|
|
||||||
if(!fMasterNode){
|
if(!fMasterNode){
|
||||||
|
@ -222,7 +222,7 @@ class CDarksendSession
|
|||||||
class CDarkSendPool
|
class CDarkSendPool
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static const int MIN_PEER_PROTO_VERSION = 70057;
|
static const int MIN_PEER_PROTO_VERSION = 70058;
|
||||||
|
|
||||||
// clients entries
|
// clients entries
|
||||||
std::vector<CDarkSendEntry> myEntries;
|
std::vector<CDarkSendEntry> myEntries;
|
||||||
|
138
src/instantx.cpp
138
src/instantx.cpp
@ -22,6 +22,7 @@ std::map<uint256, CTransaction> mapTxLockReq;
|
|||||||
std::map<uint256, CTransaction> mapTxLockReqRejected;
|
std::map<uint256, CTransaction> mapTxLockReqRejected;
|
||||||
std::map<uint256, int> mapTxLockVote;
|
std::map<uint256, int> mapTxLockVote;
|
||||||
std::map<uint256, CTransactionLock> mapTxLocks;
|
std::map<uint256, CTransactionLock> mapTxLocks;
|
||||||
|
std::map<COutPoint, uint256> mapLockedInputs;
|
||||||
std::map<uint256, int64_t> mapUnknownVotes; //track votes with no tx for DOS
|
std::map<uint256, int64_t> mapUnknownVotes; //track votes with no tx for DOS
|
||||||
int nCompleteTXLocks;
|
int nCompleteTXLocks;
|
||||||
|
|
||||||
@ -53,17 +54,6 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nTxAge = 0;
|
|
||||||
BOOST_REVERSE_FOREACH(CTxIn i, tx.vin){
|
|
||||||
nTxAge = GetInputAge(i);
|
|
||||||
if(nTxAge < 6)
|
|
||||||
{
|
|
||||||
LogPrintf("ProcessMessageInstantX::txlreq - Transaction not found / too new: %d / %s\n", nTxAge, tx.GetHash().ToString().c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int nBlockHeight = chainActive.Tip()->nHeight - nTxAge; //calculate the height
|
|
||||||
|
|
||||||
BOOST_FOREACH(const CTxOut o, tx.vout){
|
BOOST_FOREACH(const CTxOut o, tx.vout){
|
||||||
if(!o.scriptPubKey.IsNormalPaymentScript()){
|
if(!o.scriptPubKey.IsNormalPaymentScript()){
|
||||||
printf ("ProcessMessageInstantX::txlreq - Invalid Script %s\n", tx.ToString().c_str());
|
printf ("ProcessMessageInstantX::txlreq - Invalid Script %s\n", tx.ToString().c_str());
|
||||||
@ -71,13 +61,16 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nBlockHeight = CreateNewLock(tx);
|
||||||
|
|
||||||
bool fMissingInputs = false;
|
bool fMissingInputs = false;
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
|
|
||||||
|
|
||||||
if (AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs))
|
if (AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs))
|
||||||
{
|
{
|
||||||
RelayTransactionLockReq(tx, tx.GetHash());
|
RelayTransactionLockReq(tx, tx.GetHash());
|
||||||
DoConsensusVote(tx, true, nBlockHeight);
|
DoConsensusVote(tx, nBlockHeight);
|
||||||
|
|
||||||
mapTxLockReq.insert(make_pair(tx.GetHash(), tx));
|
mapTxLockReq.insert(make_pair(tx.GetHash(), tx));
|
||||||
|
|
||||||
@ -94,13 +87,18 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
|
|||||||
// can we get the conflicting transaction as proof?
|
// can we get the conflicting transaction as proof?
|
||||||
|
|
||||||
RelayTransactionLockReq(tx, inv.hash);
|
RelayTransactionLockReq(tx, inv.hash);
|
||||||
DoConsensusVote(tx, false, nBlockHeight);
|
|
||||||
|
|
||||||
LogPrintf("ProcessMessageInstantX::txlreq - Transaction Lock Request: %s %s : rejected %s\n",
|
LogPrintf("ProcessMessageInstantX::txlreq - Transaction Lock Request: %s %s : rejected %s\n",
|
||||||
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
|
pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(),
|
||||||
tx.GetHash().ToString().c_str()
|
tx.GetHash().ToString().c_str()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
BOOST_FOREACH(const CTxIn& in, tx.vin){
|
||||||
|
if(!mapLockedInputs.count(in.prevout)){
|
||||||
|
mapLockedInputs.insert(make_pair(in.prevout, tx.GetHash()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// resolve conflicts
|
// resolve conflicts
|
||||||
std::map<uint256, CTransactionLock>::iterator i = mapTxLocks.find(tx.GetHash());
|
std::map<uint256, CTransactionLock>::iterator i = mapTxLocks.find(tx.GetHash());
|
||||||
if (i != mapTxLocks.end()){
|
if (i != mapTxLocks.end()){
|
||||||
@ -109,19 +107,8 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
|
|||||||
LogPrintf("ProcessMessageInstantX::txlreq - Found Existing Complete IX Lock\n");
|
LogPrintf("ProcessMessageInstantX::txlreq - Found Existing Complete IX Lock\n");
|
||||||
|
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
bool fMissingInputs = false;
|
|
||||||
DisconnectBlockAndInputs(state, tx);
|
DisconnectBlockAndInputs(state, tx);
|
||||||
|
mapTxLockReq.insert(make_pair(tx.GetHash(), tx));
|
||||||
if (AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs))
|
|
||||||
{
|
|
||||||
LogPrintf("ProcessMessageInstantX::txlreq - Transaction Lock Request : accepted (resolved) %s\n",
|
|
||||||
tx.GetHash().ToString().c_str()
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
LogPrintf("ERROR: InstantX::ProcessConsensusVote - Transaction Lock Request : rejected (failed to resolve) %s\n",
|
|
||||||
tx.GetHash().ToString().c_str()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,12 +204,51 @@ bool IsIXTXValid(const CTransaction& txCollateral){
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t CreateNewLock(CTransaction tx)
|
||||||
|
{
|
||||||
|
|
||||||
|
int64_t nTxAge = 0;
|
||||||
|
BOOST_REVERSE_FOREACH(CTxIn i, tx.vin){
|
||||||
|
nTxAge = GetInputAge(i);
|
||||||
|
if(nTxAge < 6)
|
||||||
|
{
|
||||||
|
LogPrintf("CreateNewLock - Transaction not found / too new: %d / %s\n", nTxAge, tx.GetHash().ToString().c_str());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Use a blockheight newer than the input.
|
||||||
|
This prevents attackers from using transaction mallibility to predict which masternodes
|
||||||
|
they'll use.
|
||||||
|
*/
|
||||||
|
int nBlockHeight = (chainActive.Tip()->nHeight - nTxAge)+4;
|
||||||
|
|
||||||
|
if (!mapTxLocks.count(tx.GetHash())){
|
||||||
|
LogPrintf("CreateNewLock - New Transaction Lock %s !\n", tx.GetHash().ToString().c_str());
|
||||||
|
|
||||||
|
CTransactionLock newLock;
|
||||||
|
newLock.nBlockHeight = nBlockHeight;
|
||||||
|
newLock.nExpiration = GetTime()+(60*60);
|
||||||
|
newLock.txHash = tx.GetHash();
|
||||||
|
mapTxLocks.insert(make_pair(tx.GetHash(), newLock));
|
||||||
|
} else {
|
||||||
|
mapTxLocks[tx.GetHash()].nBlockHeight = nBlockHeight;
|
||||||
|
if(fDebug) LogPrintf("CreateNewLock - Transaction Lock Exists %s !\n", tx.GetHash().ToString().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return nBlockHeight;
|
||||||
|
}
|
||||||
|
|
||||||
// check if we need to vote on this transaction
|
// check if we need to vote on this transaction
|
||||||
void DoConsensusVote(CTransaction& tx, bool approved, int64_t nBlockHeight)
|
void DoConsensusVote(CTransaction& tx, int64_t nBlockHeight)
|
||||||
{
|
{
|
||||||
if(!fMasterNode) return;
|
if(!fMasterNode) return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
nBlockHeight calculated from the transaction is the authoritive source
|
||||||
|
*/
|
||||||
|
|
||||||
CConsensusVote ctx;
|
CConsensusVote ctx;
|
||||||
ctx.vinMasternode = activeMasternode.vin;
|
ctx.vinMasternode = activeMasternode.vin;
|
||||||
ctx.txHash = tx.GetHash();
|
ctx.txHash = tx.GetHash();
|
||||||
@ -258,7 +284,7 @@ bool ProcessConsensusVote(CConsensusVote& ctx)
|
|||||||
|
|
||||||
if(n > 10)
|
if(n > 10)
|
||||||
{
|
{
|
||||||
LogPrintf("InstantX::ProcessConsensusVote - Masternode not in the top 10\n");
|
LogPrintf("InstantX::ProcessConsensusVote - Masternode not in the top 10 (%d)\n", n);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,7 +298,7 @@ bool ProcessConsensusVote(CConsensusVote& ctx)
|
|||||||
LogPrintf("InstantX::ProcessConsensusVote - New Transaction Lock %s !\n", ctx.txHash.ToString().c_str());
|
LogPrintf("InstantX::ProcessConsensusVote - New Transaction Lock %s !\n", ctx.txHash.ToString().c_str());
|
||||||
|
|
||||||
CTransactionLock newLock;
|
CTransactionLock newLock;
|
||||||
newLock.nBlockHeight = ctx.nBlockHeight;
|
newLock.nBlockHeight = 0;
|
||||||
newLock.nExpiration = GetTime()+(60*60);
|
newLock.nExpiration = GetTime()+(60*60);
|
||||||
newLock.txHash = ctx.txHash;
|
newLock.txHash = ctx.txHash;
|
||||||
mapTxLocks.insert(make_pair(ctx.txHash, newLock));
|
mapTxLocks.insert(make_pair(ctx.txHash, newLock));
|
||||||
@ -290,8 +316,21 @@ bool ProcessConsensusVote(CConsensusVote& ctx)
|
|||||||
if((*i).second.CountSignatures() >= INSTANTX_SIGNATURES_REQUIRED){
|
if((*i).second.CountSignatures() >= INSTANTX_SIGNATURES_REQUIRED){
|
||||||
if(fDebug) LogPrintf("InstantX::ProcessConsensusVote - Transaction Lock Is Complete %s !\n", (*i).second.GetHash().ToString().c_str());
|
if(fDebug) LogPrintf("InstantX::ProcessConsensusVote - Transaction Lock Is Complete %s !\n", (*i).second.GetHash().ToString().c_str());
|
||||||
|
|
||||||
if(pwalletMain->UpdatedTransaction((*i).second.txHash)){
|
#ifdef ENABLE_WALLET
|
||||||
nCompleteTXLocks++;
|
if(pwalletMain){
|
||||||
|
if(pwalletMain->UpdatedTransaction((*i).second.txHash)){
|
||||||
|
nCompleteTXLocks++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(mapTxLockReq.count(ctx.txHash)){
|
||||||
|
CTransaction& tx = mapTxLockReq[ctx.txHash];
|
||||||
|
BOOST_FOREACH(const CTxIn& in, tx.vin){
|
||||||
|
if(!mapLockedInputs.count(in.prevout)){
|
||||||
|
mapLockedInputs.insert(make_pair(in.prevout, ctx.txHash));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve conflicts
|
// resolve conflicts
|
||||||
@ -299,20 +338,7 @@ bool ProcessConsensusVote(CConsensusVote& ctx)
|
|||||||
//if this tx lock was rejected, we need to remove the conflicting blocks
|
//if this tx lock was rejected, we need to remove the conflicting blocks
|
||||||
if(mapTxLockReqRejected.count((*i).second.txHash)){
|
if(mapTxLockReqRejected.count((*i).second.txHash)){
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
bool fMissingInputs = false;
|
|
||||||
DisconnectBlockAndInputs(state, mapTxLockReqRejected[(*i).second.txHash]);
|
DisconnectBlockAndInputs(state, mapTxLockReqRejected[(*i).second.txHash]);
|
||||||
|
|
||||||
if (AcceptToMemoryPool(mempool, state, mapTxLockReqRejected[(*i).second.txHash], true, &fMissingInputs))
|
|
||||||
{
|
|
||||||
LogPrintf("ProcessMessageInstantX::txlreq - Transaction Lock Request : accepted (resolved) %s\n",
|
|
||||||
mapTxLockReqRejected[(*i).second.txHash].GetHash().ToString().c_str()
|
|
||||||
);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
LogPrintf("ERROR: InstantX::ProcessConsensusVote - Transaction Lock Request : rejected (failed to resolve) %s\n",
|
|
||||||
mapTxLockReqRejected[(*i).second.txHash].GetHash().ToString().c_str()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -347,6 +373,17 @@ void CleanTransactionLocksList()
|
|||||||
while(it != mapTxLocks.end()) {
|
while(it != mapTxLocks.end()) {
|
||||||
if(GetTime() > it->second.nExpiration){ //keep them for an hour
|
if(GetTime() > it->second.nExpiration){ //keep them for an hour
|
||||||
LogPrintf("Removing old transaction lock %s\n", it->second.txHash.ToString().c_str());
|
LogPrintf("Removing old transaction lock %s\n", it->second.txHash.ToString().c_str());
|
||||||
|
|
||||||
|
if(mapTxLockReq.count(it->second.txHash)){
|
||||||
|
CTransaction& tx = mapTxLockReq[it->second.txHash];
|
||||||
|
|
||||||
|
BOOST_FOREACH(const CTxIn& in, tx.vin)
|
||||||
|
mapLockedInputs.erase(in.prevout);
|
||||||
|
|
||||||
|
mapTxLockReq.erase(it->second.txHash);
|
||||||
|
mapTxLockReqRejected.erase(it->second.txHash);
|
||||||
|
}
|
||||||
|
|
||||||
mapTxLocks.erase(it++);
|
mapTxLocks.erase(it++);
|
||||||
} else {
|
} else {
|
||||||
it++;
|
it++;
|
||||||
@ -466,5 +503,18 @@ void CTransactionLock::AddSignature(CConsensusVote cv)
|
|||||||
|
|
||||||
int CTransactionLock::CountSignatures()
|
int CTransactionLock::CountSignatures()
|
||||||
{
|
{
|
||||||
return vecConsensusVotes.size();
|
/*
|
||||||
|
Only count signatures where the BlockHeight matches the transaction's blockheight.
|
||||||
|
The votes have no proof it's the correct blockheight
|
||||||
|
*/
|
||||||
|
|
||||||
|
if(nBlockHeight == 0) return -1;
|
||||||
|
|
||||||
|
int n = 0;
|
||||||
|
BOOST_FOREACH(CConsensusVote v, vecConsensusVotes){
|
||||||
|
if(v.nBlockHeight == nBlockHeight){
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
@ -23,18 +23,22 @@ class CConsensusVote;
|
|||||||
class CTransaction;
|
class CTransaction;
|
||||||
class CTransactionLock;
|
class CTransactionLock;
|
||||||
|
|
||||||
static const int MIN_INSTANTX_PROTO_VERSION = 70057;
|
static const int MIN_INSTANTX_PROTO_VERSION = 70058;
|
||||||
|
|
||||||
extern map<uint256, CTransaction> mapTxLockReq;
|
extern map<uint256, CTransaction> mapTxLockReq;
|
||||||
extern map<uint256, CTransactionLock> mapTxLocks;
|
extern map<uint256, CTransactionLock> mapTxLocks;
|
||||||
|
extern std::map<COutPoint, uint256> mapLockedInputs;
|
||||||
extern int nCompleteTXLocks;
|
extern int nCompleteTXLocks;
|
||||||
|
|
||||||
|
|
||||||
|
int64_t CreateNewLock(CTransaction tx);
|
||||||
|
|
||||||
bool IsIXTXValid(const CTransaction& txCollateral);
|
bool IsIXTXValid(const CTransaction& txCollateral);
|
||||||
|
|
||||||
void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
|
void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
|
||||||
|
|
||||||
//check if we need to vote on this transaction
|
//check if we need to vote on this transaction
|
||||||
void DoConsensusVote(CTransaction& tx, bool approved, int64_t nBlockHeight);
|
void DoConsensusVote(CTransaction& tx, int64_t nBlockHeight);
|
||||||
|
|
||||||
//process consensus vote message
|
//process consensus vote message
|
||||||
bool ProcessConsensusVote(CConsensusVote& ctx);
|
bool ProcessConsensusVote(CConsensusVote& ctx);
|
||||||
|
299
src/main.cpp
299
src/main.cpp
@ -894,6 +894,18 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
|||||||
if (pool.exists(hash))
|
if (pool.exists(hash))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// ----------- instantX transaction scanning -----------
|
||||||
|
|
||||||
|
BOOST_FOREACH(const CTxIn& in, tx.vin){
|
||||||
|
if(mapLockedInputs.count(in.prevout)){
|
||||||
|
if(mapLockedInputs[in.prevout] != tx.GetHash()){
|
||||||
|
return state.DoS(0,
|
||||||
|
error("AcceptToMemoryPool : conflicts with existing transaction lock: %s", reason),
|
||||||
|
REJECT_INVALID, "tx-lock-conflict");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check for conflicts with in-memory transactions
|
// Check for conflicts with in-memory transactions
|
||||||
{
|
{
|
||||||
LOCK(pool.cs); // protect pool.mapNextTx
|
LOCK(pool.cs); // protect pool.mapNextTx
|
||||||
@ -909,29 +921,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ----------- instantX transaction scanning -----------
|
|
||||||
|
|
||||||
std::map<uint256, CTransactionLock>::iterator it = mapTxLocks.begin();
|
|
||||||
|
|
||||||
while(it != mapTxLocks.end()) {
|
|
||||||
if(mapTxLockReq.count((*it).second.txHash)){
|
|
||||||
CTransaction& tx2 = mapTxLockReq[(*it).second.txHash];
|
|
||||||
for (unsigned int a = 0; a < tx2.vin.size(); a++) {
|
|
||||||
//we found the locked tx in the block
|
|
||||||
if(tx2.GetHash() == tx.GetHash()) continue;
|
|
||||||
|
|
||||||
//if there's a lock, look for conflicting inputs
|
|
||||||
for (unsigned int b = 0; b < tx.vin.size(); b++) {
|
|
||||||
if(tx2.vin[a].prevout == tx.vin[b].prevout) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
it++;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
CCoinsView dummy;
|
CCoinsView dummy;
|
||||||
CCoinsViewCache view(dummy);
|
CCoinsViewCache view(dummy);
|
||||||
@ -2132,167 +2121,6 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
DisconnectBlockAndInputs
|
|
||||||
|
|
||||||
Remove conflicting blocks for successful InstantX transaction locks
|
|
||||||
This should be very rare (Probably will never happen)
|
|
||||||
*/
|
|
||||||
bool DisconnectBlockAndInputs(CValidationState &state, CTransaction txLock)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
// All modifications to the coin state will be done in this cache.
|
|
||||||
// Only when all have succeeded, we push it to pcoinsTip.
|
|
||||||
CCoinsViewCache view(*pcoinsTip, true);
|
|
||||||
|
|
||||||
CBlockIndex* BlockReading = chainActive.Tip();
|
|
||||||
CBlockIndex* pindexNew = NULL;
|
|
||||||
|
|
||||||
int HeightMin = chainActive.Tip()->nHeight-5;
|
|
||||||
bool foundConflictingTx = false;
|
|
||||||
|
|
||||||
//remove anything conflicting in the memory pool
|
|
||||||
list<CTransaction> txConflicted;
|
|
||||||
mempool.removeConflicts(txLock, txConflicted);
|
|
||||||
|
|
||||||
|
|
||||||
// List of what to disconnect (typically nothing)
|
|
||||||
vector<CBlockIndex*> vDisconnect;
|
|
||||||
|
|
||||||
for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0 && !foundConflictingTx; i++) {
|
|
||||||
vDisconnect.push_back(BlockReading);
|
|
||||||
pindexNew = BlockReading->pprev; //new best block
|
|
||||||
|
|
||||||
CBlock block;
|
|
||||||
if (!ReadBlockFromDisk(block, BlockReading))
|
|
||||||
return state.Abort(_("Failed to read block"));
|
|
||||||
|
|
||||||
// Queue memory transactions to resurrect.
|
|
||||||
// We only do this for blocks after the last checkpoint (reorganisation before that
|
|
||||||
// point should only happen with -reindex/-loadblock, or a misbehaving peer.
|
|
||||||
BOOST_FOREACH(const CTransaction& tx, block.vtx){
|
|
||||||
if (!tx.IsCoinBase() && BlockReading->nHeight > HeightMin){
|
|
||||||
BOOST_FOREACH(const CTxIn& in1, txLock.vin){
|
|
||||||
BOOST_FOREACH(const CTxIn& in2, tx.vin){
|
|
||||||
if(in1 == in2) foundConflictingTx = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (BlockReading->pprev == NULL) { assert(BlockReading); break; }
|
|
||||||
BlockReading = BlockReading->pprev;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!foundConflictingTx) {
|
|
||||||
LogPrintf("DisconnectBlockAndInputs: Can't find a conflicting transaction to inputs\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vDisconnect.size() > 0) {
|
|
||||||
LogPrintf("REORGANIZE: Disconnect Conflicting Blocks %lli blocks; %s..\n", vDisconnect.size(), pindexNew->GetBlockHash().ToString().c_str());
|
|
||||||
BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) {
|
|
||||||
LogPrintf(" -- disconnect %s\n", pindex->GetBlockHash().ToString().c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disconnect shorter branch
|
|
||||||
vector<CTransaction> vResurrect;
|
|
||||||
BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) {
|
|
||||||
CBlock block;
|
|
||||||
if (!ReadBlockFromDisk(block, pindex))
|
|
||||||
return state.Abort(_("Failed to read block"));
|
|
||||||
int64_t nStart = GetTimeMicros();
|
|
||||||
if (!DisconnectBlock(block, state, pindex, view))
|
|
||||||
return error("DisconnectBlockAndInputs/SetBestBlock() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().c_str());
|
|
||||||
if (fBenchmark)
|
|
||||||
LogPrintf("- Disconnect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
|
|
||||||
|
|
||||||
// Queue memory transactions to resurrect.
|
|
||||||
// We only do this for blocks after the last checkpoint (reorganisation before that
|
|
||||||
// point should only happen with -reindex/-loadblock, or a misbehaving peer.
|
|
||||||
BOOST_FOREACH(const CTransaction& tx, block.vtx){
|
|
||||||
if (!tx.IsCoinBase() && pindex->nHeight > HeightMin){
|
|
||||||
bool isConflict = false;
|
|
||||||
BOOST_FOREACH(const CTxIn& in1, txLock.vin){
|
|
||||||
BOOST_FOREACH(const CTxIn& in2, tx.vin){
|
|
||||||
if(in1 != in2) isConflict = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!isConflict) vResurrect.push_back(tx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
mempool.check(pcoinsTip);
|
|
||||||
|
|
||||||
// At this point, all changes have been done to the database.
|
|
||||||
// Proceed by updating the memory structures.
|
|
||||||
|
|
||||||
// Disconnect shorter branch
|
|
||||||
BOOST_FOREACH(CBlockIndex* pindex, vDisconnect)
|
|
||||||
if (pindex->pprev)
|
|
||||||
pindex->pprev->pnext = NULL;
|
|
||||||
|
|
||||||
// Resurrect memory transactions that were in the disconnected branch
|
|
||||||
BOOST_FOREACH(CTransaction& tx, vResurrect) {
|
|
||||||
// ignore validation errors in resurrected transactions
|
|
||||||
CValidationState stateDummy;
|
|
||||||
if (!tx.AcceptToMemoryPool(mempool, stateDummy, tx, true, false))
|
|
||||||
mempool.remove(tx, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update best block in wallet (so we can detect restored wallets)
|
|
||||||
|
|
||||||
if ((pindexNew->nHeight % 20160) == 0 || (!fIsInitialDownload && (pindexNew->nHeight % 144) == 0))
|
|
||||||
{
|
|
||||||
const CBlockLocator locator(pindexNew);
|
|
||||||
::SetBestChain(locator);
|
|
||||||
}
|
|
||||||
|
|
||||||
// New best block
|
|
||||||
hashBestChain = pindexNew->GetBlockHash();
|
|
||||||
chainActive.Tip() = pindexNew;
|
|
||||||
pblockindexFBBHLast = NULL;
|
|
||||||
chainActive.Tip()->nHeight = chainActive.Tip()->nHeight;
|
|
||||||
nBestChainWork = pindexNew->nChainWork;
|
|
||||||
nTimeBestReceived = GetTime();
|
|
||||||
nTransactionsUpdated++;
|
|
||||||
LogPrintf("DisconnectBlockAndInputs / SetBestChain: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f\n",
|
|
||||||
hashBestChain.ToString().c_str(), chainActive.Tip()->nHeight, log(nBestChainWork.getdouble())/log(2.0), (unsigned long)pindexNew->nChainTx,
|
|
||||||
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()).c_str(),
|
|
||||||
Checkpoints::GuessVerificationProgress(chainActive.Tip()));
|
|
||||||
|
|
||||||
// Check the version of the last 100 blocks to see if we need to upgrade:
|
|
||||||
if (!fIsInitialDownload)
|
|
||||||
{
|
|
||||||
int nUpgraded = 0;
|
|
||||||
const CBlockIndex* pindex = chainActive.Tip();
|
|
||||||
for (int i = 0; i < 100 && pindex != NULL; i++)
|
|
||||||
{
|
|
||||||
if (pindex->nVersion > CBlock::CURRENT_VERSION)
|
|
||||||
++nUpgraded;
|
|
||||||
pindex = pindex->pprev;
|
|
||||||
}
|
|
||||||
if (nUpgraded > 0)
|
|
||||||
LogPrintf("DisconnectBlockAndInputs/SetBestChain: %d of last 100 blocks above version %d\n", nUpgraded, CBlock::CURRENT_VERSION);
|
|
||||||
if (nUpgraded > 100/2)
|
|
||||||
// strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user:
|
|
||||||
strMiscWarning = _("Warning: This version is obsolete, upgrade required!");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string strCmd = GetArg("-blocknotify", "");
|
|
||||||
|
|
||||||
if (!fIsInitialDownload && !strCmd.empty())
|
|
||||||
{
|
|
||||||
boost::replace_all(strCmd, "%s", hashBestChain.GetHex());
|
|
||||||
boost::thread t(runCommand, strCmd); // thread runs free
|
|
||||||
}
|
|
||||||
|
|
||||||
*/ return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void static FlushBlockFile(bool fFinalize = false)
|
void static FlushBlockFile(bool fFinalize = false)
|
||||||
{
|
{
|
||||||
LOCK(cs_LastBlockFile);
|
LOCK(cs_LastBlockFile);
|
||||||
@ -2632,6 +2460,74 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
DisconnectBlockAndInputs
|
||||||
|
|
||||||
|
Remove conflicting blocks for successful InstantX transaction locks
|
||||||
|
This should be very rare (Probably will never happen)
|
||||||
|
*/
|
||||||
|
bool DisconnectBlockAndInputs(CValidationState &state, CTransaction txLock)
|
||||||
|
{
|
||||||
|
|
||||||
|
// All modifications to the coin state will be done in this cache.
|
||||||
|
// Only when all have succeeded, we push it to pcoinsTip.
|
||||||
|
CCoinsViewCache view(*pcoinsTip, true);
|
||||||
|
|
||||||
|
CBlockIndex* BlockReading = chainActive.Tip();
|
||||||
|
CBlockIndex* pindexNew = NULL;
|
||||||
|
|
||||||
|
bool foundConflictingTx = false;
|
||||||
|
|
||||||
|
//remove anything conflicting in the memory pool
|
||||||
|
list<CTransaction> txConflicted;
|
||||||
|
mempool.removeConflicts(txLock, txConflicted);
|
||||||
|
|
||||||
|
|
||||||
|
// List of what to disconnect (typically nothing)
|
||||||
|
vector<CBlockIndex*> vDisconnect;
|
||||||
|
|
||||||
|
for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0 && !foundConflictingTx && i < 6; i++) {
|
||||||
|
vDisconnect.push_back(BlockReading);
|
||||||
|
pindexNew = BlockReading->pprev; //new best block
|
||||||
|
|
||||||
|
CBlock block;
|
||||||
|
if (!ReadBlockFromDisk(block, BlockReading))
|
||||||
|
return state.Abort(_("Failed to read block"));
|
||||||
|
|
||||||
|
// Queue memory transactions to resurrect.
|
||||||
|
// We only do this for blocks after the last checkpoint (reorganisation before that
|
||||||
|
// point should only happen with -reindex/-loadblock, or a misbehaving peer.
|
||||||
|
BOOST_FOREACH(const CTransaction& tx, block.vtx){
|
||||||
|
if (!tx.IsCoinBase()){
|
||||||
|
BOOST_FOREACH(const CTxIn& in1, txLock.vin){
|
||||||
|
BOOST_FOREACH(const CTxIn& in2, tx.vin){
|
||||||
|
if(in1.prevout == in2.prevout) foundConflictingTx = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BlockReading->pprev == NULL) { assert(BlockReading); break; }
|
||||||
|
BlockReading = BlockReading->pprev;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!foundConflictingTx) {
|
||||||
|
LogPrintf("DisconnectBlockAndInputs: Can't find a conflicting transaction to inputs\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vDisconnect.size() > 0) {
|
||||||
|
LogPrintf("REORGANIZE: Disconnect Conflicting Blocks %lli blocks; %s..\n", vDisconnect.size(), pindexNew->GetBlockHash().ToString().c_str());
|
||||||
|
BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) {
|
||||||
|
LogPrintf(" -- disconnect %s\n", pindex->GetBlockHash().ToString().c_str());
|
||||||
|
DisconnectTip(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Make chainMostWork correspond to the chain with the most work in it, that isn't
|
// Make chainMostWork correspond to the chain with the most work in it, that isn't
|
||||||
// known to be invalid (it's however far from certain to be valid).
|
// known to be invalid (it's however far from certain to be valid).
|
||||||
void static FindMostWorkChain() {
|
void static FindMostWorkChain() {
|
||||||
@ -2919,27 +2815,17 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
|
|||||||
|
|
||||||
// ----------- instantX transaction scanning -----------
|
// ----------- instantX transaction scanning -----------
|
||||||
|
|
||||||
std::map<uint256, CTransactionLock>::iterator it = mapTxLocks.begin();
|
BOOST_FOREACH(const CTransaction& tx, block.vtx){
|
||||||
|
if (!tx.IsCoinBase()){
|
||||||
while(it != mapTxLocks.end()) {
|
BOOST_FOREACH(const CTxIn& in, tx.vin){
|
||||||
if(mapTxLockReq.count((*it).second.txHash)){
|
if(mapLockedInputs.count(in.prevout)){
|
||||||
CTransaction& tx = mapTxLockReq[(*it).second.txHash];
|
if(mapLockedInputs[in.prevout] != tx.GetHash()){
|
||||||
for (unsigned int a = 0; a < tx.vin.size(); a++) {
|
return state.DoS(0, error("CheckBlock() : found conflicting transaction with transaction lock"),
|
||||||
for (unsigned int b = 0; b < block.vtx.size(); b++) {
|
REJECT_INVALID, "conflicting-tx-ix");
|
||||||
//we found the locked tx in the block
|
|
||||||
if(tx.GetHash() == block.vtx[b].GetHash()) continue;
|
|
||||||
|
|
||||||
//if there's a lock, look for conflicting inputs
|
|
||||||
for (unsigned int c = 0; c < block.vtx[b].vin.size(); c++) {
|
|
||||||
if(tx.vin[a].prevout == block.vtx[b].vin[c].prevout) {
|
|
||||||
return state.DoS(100, error("CheckBlock() : found conflicting transaction with transaction lock"),
|
|
||||||
REJECT_INVALID, "conflicting-tx-ix");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
it++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3203,6 +3089,15 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
|
|||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
|
|
||||||
|
/*
|
||||||
|
block-a-block
|
||||||
|
|
||||||
|
std::string s = "2600c8bebd2a300b2541b3720d8a30f20b61d01813a24f5934e10a2ab81b5ed9";
|
||||||
|
if(pblock->GetHash().ToString() == s){
|
||||||
|
printf("Nope, get outta here!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*/
|
||||||
// Check for duplicate
|
// Check for duplicate
|
||||||
uint256 hash = pblock->GetHash();
|
uint256 hash = pblock->GetHash();
|
||||||
if (mapBlockIndex.count(hash))
|
if (mapBlockIndex.count(hash))
|
||||||
@ -3294,6 +3189,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
|
|||||||
if(!fLiteMode){
|
if(!fLiteMode){
|
||||||
if (!fImporting && !fReindex && chainActive.Height() > Checkpoints::GetTotalBlocksEstimate()){
|
if (!fImporting && !fReindex && chainActive.Height() > Checkpoints::GetTotalBlocksEstimate()){
|
||||||
darkSendPool.NewBlock();
|
darkSendPool.NewBlock();
|
||||||
|
masternodePayments.ProcessBlock(GetHeight()+10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4593,6 +4489,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
|||||||
CBlock block;
|
CBlock block;
|
||||||
vRecv >> block;
|
vRecv >> block;
|
||||||
|
|
||||||
|
|
||||||
LogPrint("net", "received block %s\n", block.GetHash().ToString());
|
LogPrint("net", "received block %s\n", block.GetHash().ToString());
|
||||||
// block.print();
|
// block.print();
|
||||||
|
|
||||||
|
@ -717,6 +717,7 @@ void CMasternodePayments::CleanPaymentList()
|
|||||||
|
|
||||||
bool CMasternodePayments::ProcessBlock(int nBlockHeight)
|
bool CMasternodePayments::ProcessBlock(int nBlockHeight)
|
||||||
{
|
{
|
||||||
|
|
||||||
if(!enabled) return false;
|
if(!enabled) return false;
|
||||||
CMasternodePaymentWinner winner;
|
CMasternodePaymentWinner winner;
|
||||||
|
|
||||||
@ -749,7 +750,13 @@ bool CMasternodePayments::ProcessBlock(int nBlockHeight)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(winner.nBlockHeight == 0) return false; //no masternodes available
|
//if we can't find someone to get paid, pick randomly
|
||||||
|
if(winner.nBlockHeight == 0 && vecMasternodes.size() > 1) {
|
||||||
|
winner.score = 0;
|
||||||
|
winner.nBlockHeight = nBlockHeight;
|
||||||
|
winner.vin = vecMasternodes[0].vin;
|
||||||
|
winner.payee.SetDestination(vecMasternodes[0].pubkey.GetID());
|
||||||
|
}
|
||||||
|
|
||||||
if(Sign(winner)){
|
if(Sign(winner)){
|
||||||
if(AddWinningMasternode(winner)){
|
if(AddWinningMasternode(winner)){
|
||||||
|
@ -360,7 +360,6 @@ void OverviewPage::darkSendStatus()
|
|||||||
|
|
||||||
/* ** @TODO this string creation really needs some clean ups ---vertoe ** */
|
/* ** @TODO this string creation really needs some clean ups ---vertoe ** */
|
||||||
std::ostringstream convert;
|
std::ostringstream convert;
|
||||||
convert << tr("Last Darksend message:\n").toStdString();
|
|
||||||
|
|
||||||
if(state == POOL_STATUS_ACCEPTING_ENTRIES) {
|
if(state == POOL_STATUS_ACCEPTING_ENTRIES) {
|
||||||
if(entries == 0) {
|
if(entries == 0) {
|
||||||
@ -408,13 +407,13 @@ void OverviewPage::darkSendStatus()
|
|||||||
if(state == POOL_STATUS_ERROR || state == POOL_STATUS_SUCCESS) darkSendPool.Check();
|
if(state == POOL_STATUS_ERROR || state == POOL_STATUS_SUCCESS) darkSendPool.Check();
|
||||||
|
|
||||||
QString s(convert.str().c_str());
|
QString s(convert.str().c_str());
|
||||||
|
s = tr("Last Darksend message:\n") + s;
|
||||||
|
|
||||||
if(s != ui->darksendStatus->text())
|
if(s != ui->darksendStatus->text())
|
||||||
LogPrintf("%s\n", convert.str().c_str());
|
LogPrintf("Last Darksend message: %s\n", convert.str().c_str());
|
||||||
|
|
||||||
ui->darksendStatus->setText(s);
|
ui->darksendStatus->setText(s);
|
||||||
|
|
||||||
|
|
||||||
if(darkSendPool.sessionDenom == 0){
|
if(darkSendPool.sessionDenom == 0){
|
||||||
ui->labelSubmittedDenom->setText(tr("N/A"));
|
ui->labelSubmittedDenom->setText(tr("N/A"));
|
||||||
} else {
|
} else {
|
||||||
|
@ -27,7 +27,7 @@ extern const std::string CLIENT_DATE;
|
|||||||
// network protocol versioning
|
// network protocol versioning
|
||||||
//
|
//
|
||||||
|
|
||||||
static const int PROTOCOL_VERSION = 70057;
|
static const int PROTOCOL_VERSION = 70058;
|
||||||
|
|
||||||
// intial proto version, to be increased after version/verack negotiation
|
// intial proto version, to be increased after version/verack negotiation
|
||||||
static const int INIT_PROTO_VERSION = 209;
|
static const int INIT_PROTO_VERSION = 209;
|
||||||
|
@ -1001,10 +1001,11 @@ void CWalletTx::RelayWalletTransaction(std::string strCommand)
|
|||||||
LogPrintf("Relaying wtx %s\n", hash.ToString());
|
LogPrintf("Relaying wtx %s\n", hash.ToString());
|
||||||
|
|
||||||
if(strCommand == "txlreq"){
|
if(strCommand == "txlreq"){
|
||||||
mapTxLockReq.insert(make_pair(hash, (CTransaction)*this));
|
mapTxLockReq.insert(make_pair(hash, ((CTransaction)*this)));
|
||||||
RelayTransactionLockReq((CTransaction)*this, hash, true);
|
CreateNewLock(((CTransaction)*this));
|
||||||
|
RelayTransactionLockReq(((CTransaction)*this), hash, true);
|
||||||
} else {
|
} else {
|
||||||
RelayTransaction((CTransaction)*this, hash);
|
RelayTransaction(((CTransaction)*this), hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1484,6 +1485,10 @@ bool CWallet::SelectCoins(int64_t nTargetValue, set<pair<const CWalletTx*,unsign
|
|||||||
if(out.tx->vout[out.i].nValue == v //make sure it's the denom we're looking for
|
if(out.tx->vout[out.i].nValue == v //make sure it's the denom we're looking for
|
||||||
&& nValueRet + out.tx->vout[out.i].nValue < nTargetValue + (0.1*COIN)+100 //round the amount up to .1DRK over
|
&& nValueRet + out.tx->vout[out.i].nValue < nTargetValue + (0.1*COIN)+100 //round the amount up to .1DRK over
|
||||||
&& added <= 50){ //don't add more than 50 of one denom type
|
&& added <= 50){ //don't add more than 50 of one denom type
|
||||||
|
CTxIn vin = CTxIn(out.tx->GetHash(),out.i);
|
||||||
|
int rounds = GetInputDarksendRounds(vin);
|
||||||
|
// make sure it's actually anonymized
|
||||||
|
if(rounds < nDarksendRounds) continue;
|
||||||
nValueRet += out.tx->vout[out.i].nValue;
|
nValueRet += out.tx->vout[out.i].nValue;
|
||||||
setCoinsRet.insert(make_pair(out.tx, out.i));
|
setCoinsRet.insert(make_pair(out.tx, out.i));
|
||||||
added++;
|
added++;
|
||||||
@ -1851,14 +1856,20 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
|
|||||||
|
|
||||||
if (!SelectCoins(nTotalValue, setCoins, nValueIn, coinControl, coin_type, useIX))
|
if (!SelectCoins(nTotalValue, setCoins, nValueIn, coinControl, coin_type, useIX))
|
||||||
{
|
{
|
||||||
if(coin_type == ALL_COINS)
|
if(coin_type == ALL_COINS) {
|
||||||
strFailReason = _("Insufficient funds");
|
strFailReason = _("Insufficient funds.");
|
||||||
else if (coin_type == ONLY_NONDENOMINATED)
|
} else if (coin_type == ONLY_NONDENOMINATED) {
|
||||||
strFailReason = _("Unable to locate enough Darksend non-denominated funds for this transaction");
|
strFailReason = _("Unable to locate enough Darksend non-denominated funds for this transaction.");
|
||||||
else if (coin_type == ONLY_NONDENOMINATED_NOTMN)
|
} else if (coin_type == ONLY_NONDENOMINATED_NOTMN) {
|
||||||
strFailReason = _("Unable to locate enough Darksend non-denominated funds for this transaction that are not equal 1000 DRK");
|
strFailReason = _("Unable to locate enough Darksend non-denominated funds for this transaction that are not equal 1000 DRK.");
|
||||||
else
|
} else {
|
||||||
strFailReason = _("Unable to locate enough Darksend denominated funds for this transaction");
|
strFailReason = _("Unable to locate enough Darksend denominated funds for this transaction.");
|
||||||
|
strFailReason += _("Darksend uses exact denominated amounts to send funds, you might simply need to anonymize some more coins.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(useIX){
|
||||||
|
strFailReason += _("InstantX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again.");
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user