Merge pull request #49 from jl777/dPoW

DPoW
This commit is contained in:
jl777
2016-11-15 21:49:18 -03:00
committed by GitHub
22 changed files with 292 additions and 151 deletions

View File

@@ -144,7 +144,8 @@ bool AppInit(int argc, char* argv[])
fDaemon = GetBoolArg("-daemon", false); fDaemon = GetBoolArg("-daemon", false);
if (fDaemon) if (fDaemon)
{ {
fprintf(stdout, "Komodo server starting\n"); extern char ASSETCHAINS_SYMBOL[16];
fprintf(stdout, "Komodo %s server starting\n",ASSETCHAINS_SYMBOL);
// Daemonize // Daemonize
pid_t pid = fork(); pid_t pid = fork();

View File

@@ -383,12 +383,12 @@ const CScript &CCoinsViewCache::GetSpendFor(const CTxIn& input) const
return coins->vout[input.prevout.n].scriptPubKey; return coins->vout[input.prevout.n].scriptPubKey;
} }
uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime); //uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue);
extern char ASSETCHAINS_SYMBOL[16]; extern char ASSETCHAINS_SYMBOL[16];
CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t *interestp,const CTransaction& tx,uint32_t tiptime) const CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t *interestp,const CTransaction& tx,uint32_t tiptime) const
{ {
uint32_t timestamp,minutes; int64_t interest;
*interestp = 0; *interestp = 0;
if ( tx.IsCoinBase() != 0 ) if ( tx.IsCoinBase() != 0 )
return 0; return 0;
@@ -397,19 +397,20 @@ CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t *interestp,const CTr
{ {
value = GetOutputFor(tx.vin[i]).nValue; value = GetOutputFor(tx.vin[i]).nValue;
nResult += value; nResult += value;
interest = komodo_interest(nHeight,value,tx.nLockTime,tiptime);
#ifdef KOMODO_ENABLE_INTEREST #ifdef KOMODO_ENABLE_INTEREST
if ( ASSETCHAINS_SYMBOL[0] == 0 && nHeight >= 60000 ) if ( ASSETCHAINS_SYMBOL[0] == 0 && nHeight >= 60000 )
{ {
if ( interest != 0 ) if ( value >= 10*COIN )
{ {
printf("nResult %.8f += interest %.8f ht.%d lock.%u tip.%u\n",(double)nResult/COIN,(double)interest/COIN,nHeight,tx.nLockTime,tiptime); int64_t interest; int32_t txheight; uint32_t locktime;
fprintf(stderr,"nResult %.8f += interest %.8f ht.%d lock.%u tip.%u\n",(double)nResult/COIN,(double)interest/COIN,nHeight,tx.nLockTime,tiptime); interest = komodo_accrued_interest(&txheight,&locktime,tx.vin[i].prevout.hash,tx.vin[i].prevout.n,0,value);
//printf("nResult %.8f += val %.8f interest %.8f ht.%d lock.%u tip.%u\n",(double)nResult/COIN,(double)value/COIN,(double)interest/COIN,txheight,locktime,tiptime);
//fprintf(stderr,"nResult %.8f += val %.8f interest %.8f ht.%d lock.%u tip.%u\n",(double)nResult/COIN,(double)value/COIN,(double)interest/COIN,txheight,locktime,tiptime);
nResult += interest;
(*interestp) += interest;
} }
nResult += interest;
} }
#endif #endif
(*interestp) += interest;
} }
nResult += tx.GetJoinSplitValueIn(); nResult += tx.GetJoinSplitValueIn();

View File

@@ -87,14 +87,14 @@ public:
//! version of the CTransaction; accesses to this value should probably check for nHeight as well, //! version of the CTransaction; accesses to this value should probably check for nHeight as well,
//! as new tx version will probably only be introduced at certain heights //! as new tx version will probably only be introduced at certain heights
int nVersion; int nVersion;
uint32_t nLockTime; //uint32_t nLockTime;
void FromTx(const CTransaction &tx, int nHeightIn) { void FromTx(const CTransaction &tx, int nHeightIn) {
fCoinBase = tx.IsCoinBase(); fCoinBase = tx.IsCoinBase();
vout = tx.vout; vout = tx.vout;
nHeight = nHeightIn; nHeight = nHeightIn;
nVersion = tx.nVersion; nVersion = tx.nVersion;
nLockTime = tx.nLockTime; //nLockTime = tx.nLockTime;
ClearUnspendable(); ClearUnspendable();
} }

View File

@@ -455,7 +455,8 @@ std::string HelpMessage(HelpMessageMode mode)
std::string LicenseInfo() std::string LicenseInfo()
{ {
return FormatParagraph(strprintf(_("Copyright (C) 2009-%i The Bitcoin Core Developers"), COPYRIGHT_YEAR)) + "\n" + return FormatParagraph(strprintf(_("Copyright (C) 2009-%i The Bitcoin Core Developers"), COPYRIGHT_YEAR)) + "\n" +
FormatParagraph(strprintf(_("Copyright (C) 2015-%i The Zcash Developers"), COPYRIGHT_YEAR)) + "\n" + FormatParagraph(strprintf(_("Copyright (C) 2015-%i The Zcash Developers"), COPYRIGHT_YEAR)) + "\n" +
FormatParagraph(strprintf(_("Copyright (C) 2015-%i jl777 and SuperNET developers"), COPYRIGHT_YEAR)) + "\n" +
"\n" + "\n" +
FormatParagraph(_("This is experimental software.")) + "\n" + FormatParagraph(_("This is experimental software.")) + "\n" +
"\n" + "\n" +
@@ -929,7 +930,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// Sanity check // Sanity check
if (!InitSanityCheck()) if (!InitSanityCheck())
return InitError(_("Initialization sanity check failed. Zcash is shutting down.")); return InitError(_("Initialization sanity check failed. Komodo is shutting down."));
std::string strDataDir = GetDataDir().string(); std::string strDataDir = GetDataDir().string();
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
@@ -945,9 +946,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
try { try {
static boost::interprocess::file_lock lock(pathLockFile.string().c_str()); static boost::interprocess::file_lock lock(pathLockFile.string().c_str());
if (!lock.try_lock()) if (!lock.try_lock())
return InitError(strprintf(_("Cannot obtain a lock on data directory %s. Zcash is probably already running."), strDataDir)); return InitError(strprintf(_("Cannot obtain a lock on data directory %s. Komodo is probably already running."), strDataDir));
} catch(const boost::interprocess::interprocess_exception& e) { } catch(const boost::interprocess::interprocess_exception& e) {
return InitError(strprintf(_("Cannot obtain a lock on data directory %s. Zcash is probably already running.") + " %s.", strDataDir, e.what())); return InitError(strprintf(_("Cannot obtain a lock on data directory %s. Komodo is probably already running.") + " %s.", strDataDir, e.what()));
} }
#ifndef WIN32 #ifndef WIN32
@@ -956,7 +957,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (GetBoolArg("-shrinkdebugfile", !fDebug)) if (GetBoolArg("-shrinkdebugfile", !fDebug))
ShrinkDebugFile(); ShrinkDebugFile();
LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
LogPrintf("Zcash version %s (%s)\n", FormatFullVersion(), CLIENT_DATE); LogPrintf("Komodo version %s (%s)\n", FormatFullVersion(), CLIENT_DATE);
LogPrintf("Using OpenSSL version %s\n", SSLeay_version(SSLEAY_VERSION)); LogPrintf("Using OpenSSL version %s\n", SSLeay_version(SSLEAY_VERSION));
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0)); LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0));

View File

@@ -29,6 +29,11 @@ using namespace std;
#include "komodo_interest.h" #include "komodo_interest.h"
uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue)
{
return(0);
}
static bool fCreateBlank; static bool fCreateBlank;
static map<string,UniValue> registers; static map<string,UniValue> registers;

View File

@@ -20,7 +20,7 @@
// 0. optimize assetchains RT loop // 0. optimize assetchains RT loop
// 1. error check fiat redeem amounts // 1. error check fiat redeem amounts
// 2. net balance limiter // 2. net balance limiter
// 3. verify: interest payment, ratification, reorgs // 3. verify: reorgs
// 4. automate notarization fee payouts // 4. automate notarization fee payouts
// 5. automated distribution of test REVS snapshot // 5. automated distribution of test REVS snapshot

View File

@@ -547,3 +547,38 @@ int32_t komodo_checkpoint(int32_t *notarized_heightp,int32_t nHeight,uint256 has
fprintf(stderr,"couldnt find notary_hash %s ht.%d\n",notarized_hash.ToString().c_str(),notarized_height); fprintf(stderr,"couldnt find notary_hash %s ht.%d\n",notarized_hash.ToString().c_str(),notarized_height);
return(0); return(0);
} }
uint32_t komodo_interest_args(int32_t *txheightp,uint32_t *tiptimep,uint64_t *valuep,uint256 hash,int32_t n)
{
LOCK(cs_main);
CTransaction tx; uint256 hashBlock; CBlockIndex *pindex,*tipindex;
if ( !GetTransaction(hash,tx,hashBlock,true) )
return(0);
uint32_t locktime = 0;
if ( n < tx.vout.size() )
{
if ( (pindex= mapBlockIndex[hashBlock]) != 0 && (tipindex= chainActive.Tip()) != 0 )
{
*valuep = tx.vout[n].nValue;
*txheightp = pindex->nHeight;
*tiptimep = tipindex->nTime;
locktime = tx.nLockTime;
//fprintf(stderr,"tx locktime.%u %.8f height.%d | tiptime.%u\n",locktime,(double)*valuep/COIN,*txheightp,*tiptimep);
}
}
return(locktime);
}
uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue)
{
uint64_t value; uint32_t tiptime;
if ( (*locktimep= komodo_interest_args(txheightp,&tiptime,&value,hash,n)) != 0 )
{
if ( (checkvalue == 0 || value == checkvalue) && (checkheight == 0 || *txheightp == checkheight) )
return(komodo_interest(*txheightp,value,*locktimep,tiptime));
//fprintf(stderr,"nValue %llu lock.%u:%u nTime.%u -> %llu\n",(long long)coins.vout[n].nValue,coins.nLockTime,timestamp,pindex->nTime,(long long)interest);
else fprintf(stderr,"komodo_accrued_interest value mismatch %llu vs %llu or height mismatch %d vs %d\n",(long long)value,(long long)checkvalue,*txheightp,checkheight);
}
return(0);
}

View File

@@ -15,7 +15,7 @@
#define KOMODO_INTEREST ((uint64_t)(0.05 * COIN)) // 5% #define KOMODO_INTEREST ((uint64_t)(0.05 * COIN)) // 5%
uint64_t komodo_accrued_interest(int32_t height,int64_t paidinterest) uint64_t komodo_earned_interest(int32_t height,int64_t paidinterest)
{ {
static uint64_t *interests; static int32_t maxheight; static uint64_t *interests; static int32_t maxheight;
uint64_t total; int32_t ind,incr = 100000; uint64_t total; int32_t ind,incr = 100000;
@@ -50,25 +50,26 @@ uint64_t komodo_accrued_interest(int32_t height,int64_t paidinterest)
uint64_t komodo_moneysupply(int32_t height) uint64_t komodo_moneysupply(int32_t height)
{ {
if ( height <= 1 ) if ( height <= 1 || ASSETCHAINS_SYMBOL[0] == 0 )
return(0); return(0);
else return(COIN * 100000000 + (height-1) * 3 + komodo_accrued_interest(height,-1)); else return(COIN * 100000000 + (height-1) * 3 + komodo_earned_interest(height,-1));
} }
uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime) uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime)
{ {
int32_t minutes; uint64_t numerator,denominator,interest = 0; int32_t minutes; uint64_t numerator,denominator,interest = 0;
if ( komodo_moneysupply(txheight) < MAX_MONEY && nLockTime >= LOCKTIME_THRESHOLD && tiptime != 0 && nLockTime < tiptime && nValue >= COIN ) if ( komodo_moneysupply(txheight) < MAX_MONEY && nLockTime >= LOCKTIME_THRESHOLD && tiptime != 0 && nLockTime < tiptime && nValue >= 10*COIN )
{ {
if ( (minutes= (tiptime - nLockTime) / 60) > 60 ) if ( (minutes= (tiptime - nLockTime) / 60) >= 60 )
{ {
numerator = (nValue * KOMODO_INTEREST); numerator = (nValue * KOMODO_INTEREST);
denominator = (((uint64_t)365 * 24 * 60) / minutes); denominator = (((uint64_t)365 * 24 * 60) / minutes);
if ( denominator == 0 ) if ( denominator == 0 )
denominator = 1; // max KOMODO_INTEREST per transfer, do it at least annually! denominator = 1; // max KOMODO_INTEREST per transfer, do it at least annually!
interest = (numerator / denominator) / COIN; interest = (numerator / denominator) / COIN;
//fprintf(stderr,"komodo_interest %lld %.8f nLockTime.%u tiptime.%u minutes.%d interest %lld %.8f (%llu / %llu)\n",(long long)nValue,dstr(nValue),nLockTime,tiptime,minutes,(long long)interest,dstr(interest),(long long)numerator,(long long)denominator); //fprintf(stderr,"komodo_interest %lld %.8f nLockTime.%u tiptime.%u minutes.%d interest %lld %.8f (%llu / %llu)\n",(long long)nValue,(double)nValue/COIN,nLockTime,tiptime,minutes,(long long)interest,(double)interest/COIN,(long long)numerator,(long long)denominator);
} }
} }
return(interest); return(interest);
} }

View File

@@ -1718,6 +1718,21 @@ bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, c
// Check for negative or overflow input values // Check for negative or overflow input values
nValueIn += coins->vout[prevout.n].nValue; nValueIn += coins->vout[prevout.n].nValue;
#ifdef KOMODO_ENABLE_INTEREST
if ( ASSETCHAINS_SYMBOL[0] == 0 && chainActive.Tip() != 0 && chainActive.Tip()->nHeight >= 60000 )
{
if ( coins->vout[prevout.n].nValue >= 10*COIN )
{
int64_t interest; int32_t txheight; uint32_t locktime;
if ( (interest= komodo_accrued_interest(&txheight,&locktime,prevout.hash,prevout.n,0,coins->vout[prevout.n].nValue)) != 0 )
{
//printf("checkResult %.8f += val %.8f interest %.8f ht.%d lock.%u tip.%u\n",(double)nValueIn/COIN,(double)coins->vout[prevout.n].nValue/COIN,(double)interest/COIN,txheight,locktime,chainActive.Tip()->nTime);
//fprintf(stderr,"checkResult %.8f += val %.8f interest %.8f ht.%d lock.%u tip.%u\n",(double)nValueIn/COIN,(double)coins->vout[prevout.n].nValue/COIN,(double)interest/COIN,txheight,locktime,chainActive.Tip()->nTime);
nValueIn += interest;
}
}
}
#endif
if (!MoneyRange(coins->vout[prevout.n].nValue) || !MoneyRange(nValueIn)) if (!MoneyRange(coins->vout[prevout.n].nValue) || !MoneyRange(nValueIn))
return state.DoS(100, error("CheckInputs(): txin values out of range"), return state.DoS(100, error("CheckInputs(): txin values out of range"),
REJECT_INVALID, "bad-txns-inputvalues-outofrange"); REJECT_INVALID, "bad-txns-inputvalues-outofrange");
@@ -1730,9 +1745,8 @@ bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, c
REJECT_INVALID, "bad-txns-inputvalues-outofrange"); REJECT_INVALID, "bad-txns-inputvalues-outofrange");
if (nValueIn < tx.GetValueOut()) if (nValueIn < tx.GetValueOut())
return state.DoS(100, error("CheckInputs(): %s value in (%s) < value out (%s)", return state.DoS(100, error("CheckInputs(): %s value in (%s) < value out (%s) diff %.8f",
tx.GetHash().ToString(), FormatMoney(nValueIn), FormatMoney(tx.GetValueOut())), tx.GetHash().ToString(), FormatMoney(nValueIn), FormatMoney(tx.GetValueOut()),((double)nValueIn - tx.GetValueOut())/COIN),REJECT_INVALID, "bad-txns-in-belowout");
REJECT_INVALID, "bad-txns-in-belowout");
// Tally transaction fees // Tally transaction fees
CAmount nTxFee = nValueIn - tx.GetValueOut(); CAmount nTxFee = nValueIn - tx.GetValueOut();
@@ -1743,7 +1757,7 @@ bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, c
if (!MoneyRange(nFees)) if (!MoneyRange(nFees))
return state.DoS(100, error("CheckInputs(): nFees out of range"), return state.DoS(100, error("CheckInputs(): nFees out of range"),
REJECT_INVALID, "bad-txns-fee-outofrange"); REJECT_INVALID, "bad-txns-fee-outofrange");
//fprintf(stderr,"nFees %.8f\n",(double)nFees/COIN);
// The first loop above does all the inexpensive checks. // The first loop above does all the inexpensive checks.
// Only if ALL inputs pass do we perform expensive ECDSA signature checks. // Only if ALL inputs pass do we perform expensive ECDSA signature checks.
// Helps prevent CPU exhaustion attacks. // Helps prevent CPU exhaustion attacks.
@@ -2230,7 +2244,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
return false; return false;
control.Add(vChecks); control.Add(vChecks);
} }
komodo_accrued_interest(pindex->nHeight,sum); komodo_earned_interest(pindex->nHeight,sum);
CTxUndo undoDummy; CTxUndo undoDummy;
if (i > 0) { if (i > 0) {
blockundo.vtxundo.push_back(CTxUndo()); blockundo.vtxundo.push_back(CTxUndo());

View File

@@ -479,7 +479,7 @@ static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& rese
{ {
LOCK(cs_main); LOCK(cs_main);
if (pblock->hashPrevBlock != chainActive.Tip()->GetBlockHash()) if (pblock->hashPrevBlock != chainActive.Tip()->GetBlockHash())
return error("ZcashMiner: generated block is stale"); return error("KomodoMiner: generated block is stale");
} }
// Remove key from key pool // Remove key from key pool
@@ -495,7 +495,7 @@ static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& rese
// Process this block the same as if we had received it from another node // Process this block the same as if we had received it from another node
CValidationState state; CValidationState state;
if (!ProcessNewBlock(chainActive.Tip()->nHeight+1,state, NULL, pblock, true, NULL)) if (!ProcessNewBlock(chainActive.Tip()->nHeight+1,state, NULL, pblock, true, NULL))
return error("ZcashMiner: ProcessNewBlock, block not accepted"); return error("KomodoMiner: ProcessNewBlock, block not accepted");
minedBlocks.increment(); minedBlocks.increment();
@@ -506,9 +506,9 @@ int32_t komodo_baseid(char *origbase);
void static BitcoinMiner(CWallet *pwallet) void static BitcoinMiner(CWallet *pwallet)
{ {
LogPrintf("ZcashMiner started\n"); LogPrintf("KomodoMiner started\n");
SetThreadPriority(THREAD_PRIORITY_LOWEST); SetThreadPriority(THREAD_PRIORITY_LOWEST);
RenameThread("zcash-miner"); RenameThread("komodo-miner");
const CChainParams& chainparams = Params(); const CChainParams& chainparams = Params();
// Each thread has its own key and counter // Each thread has its own key and counter
@@ -583,12 +583,12 @@ void static BitcoinMiner(CWallet *pwallet)
unique_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey)); unique_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey));
if (!pblocktemplate.get()) if (!pblocktemplate.get())
{ {
LogPrintf("Error in ZcashMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n"); LogPrintf("Error in KomodoMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n");
return; return;
} }
CBlock *pblock = &pblocktemplate->block; CBlock *pblock = &pblocktemplate->block;
IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
LogPrintf("Running ZcashMiner.%s with %u transactions in block (%u bytes)\n",solver.c_str(),pblock->vtx.size(),::GetSerializeSize(*pblock,SER_NETWORK,PROTOCOL_VERSION)); LogPrintf("Running KomodoMiner.%s with %u transactions in block (%u bytes)\n",solver.c_str(),pblock->vtx.size(),::GetSerializeSize(*pblock,SER_NETWORK,PROTOCOL_VERSION));
// //
// Search // Search
// //
@@ -641,7 +641,7 @@ void static BitcoinMiner(CWallet *pwallet)
} }
// Found a solution // Found a solution
SetThreadPriority(THREAD_PRIORITY_NORMAL); SetThreadPriority(THREAD_PRIORITY_NORMAL);
LogPrintf("ZcashMiner:\n"); LogPrintf("KomodoMiner:\n");
LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", pblock->GetHash().GetHex(), hashTarget.GetHex()); LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", pblock->GetHash().GetHex(), hashTarget.GetHex());
if (ProcessBlockFound(pblock, *pwallet, reservekey)) { if (ProcessBlockFound(pblock, *pwallet, reservekey)) {
// Ignore chain updates caused by us // Ignore chain updates caused by us
@@ -755,12 +755,12 @@ void static BitcoinMiner(CWallet *pwallet)
} }
catch (const boost::thread_interrupted&) catch (const boost::thread_interrupted&)
{ {
LogPrintf("ZcashMiner terminated\n"); LogPrintf("KomodoMiner terminated\n");
throw; throw;
} }
catch (const std::runtime_error &e) catch (const std::runtime_error &e)
{ {
LogPrintf("ZcashMiner runtime error: %s\n", e.what()); LogPrintf("KomodoMiner runtime error: %s\n", e.what());
return; return;
} }
c.disconnect(); c.disconnect();

View File

@@ -127,7 +127,7 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in
} }
if ( nonz == 0 ) if ( nonz == 0 )
return(true); // will come back via different path with pubkey set return(true); // will come back via different path with pubkey set
if ( height > 60000 ) //if ( height > 60000 )
{ {
if ( notaryid >= 0 ) if ( notaryid >= 0 )
{ {
@@ -142,7 +142,7 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in
} }
} }
} }
else /*else
{ {
if ( special > 0 ) // special notary id == (height % numnotaries) if ( special > 0 ) // special notary id == (height % numnotaries)
{ {
@@ -151,12 +151,10 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in
bnTarget.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow); bnTarget.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
flag = 1; flag = 1;
} }
} }*/
} }
if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit)) if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit))
return error("CheckProofOfWork(): nBits below minimum work"); return error("CheckProofOfWork(): nBits below minimum work");
if ( height > 70000 )
bnTarget /= 64;
// Check proof of work matches claimed amount // Check proof of work matches claimed amount
if ( UintToArith256(hash) > bnTarget ) if ( UintToArith256(hash) > bnTarget )
{ {

View File

@@ -239,7 +239,7 @@ class CTxOut
public: public:
CAmount nValue; CAmount nValue;
CScript scriptPubKey; CScript scriptPubKey;
uint64_t interest;
CTxOut() CTxOut()
{ {
SetNull(); SetNull();

View File

@@ -386,6 +386,7 @@ uint64_t komodo_paxprice(uint64_t *seedp,int32_t height,char *base,char *rel,uin
int32_t komodo_paxprices(int32_t *heights,uint64_t *prices,int32_t max,char *base,char *rel); int32_t komodo_paxprices(int32_t *heights,uint64_t *prices,int32_t max,char *base,char *rel);
int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height); int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height);
char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey_or_rmd160,int32_t len); char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey_or_rmd160,int32_t len);
uint32_t komodo_interest_args(int32_t *txheightp,uint32_t *tiptimep,uint64_t *valuep,uint256 hash,int32_t n);
Value notaries(const Array& params, bool fHelp) Value notaries(const Array& params, bool fHelp)
{ {
@@ -504,6 +505,8 @@ Value paxprices(const Array& params, bool fHelp)
return ret; return ret;
} }
uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue);
Value gettxout(const Array& params, bool fHelp) Value gettxout(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() < 2 || params.size() > 3) if (fHelp || params.size() < 2 || params.size() > 3)
@@ -574,15 +577,9 @@ Value gettxout(const Array& params, bool fHelp)
ret.push_back(Pair("confirmations", 0)); ret.push_back(Pair("confirmations", 0));
else ret.push_back(Pair("confirmations", pindex->nHeight - coins.nHeight + 1)); else ret.push_back(Pair("confirmations", pindex->nHeight - coins.nHeight + 1));
ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue))); ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue)));
uint64_t interest; int32_t txheight; uint32_t locktime;
CBlockIndex *pblockindex = chainActive[coins.nHeight]; if ( (interest= komodo_accrued_interest(&txheight,&locktime,hash,n,coins.nHeight,coins.vout[n].nValue)) != 0 )
uint64_t interest; uint32_t timestamp=0; ret.push_back(Pair("interest", ValueFromAmount(interest)));
if ( pblockindex != 0 )
timestamp = pblockindex->nTime; // this is approx, but cant figure out how to get tx here
interest = komodo_interest(coins.nHeight,coins.vout[n].nValue,timestamp,pindex->nTime);
//fprintf(stderr,"nValue %llu lock.%u:%u nTime.%u -> %llu\n",(long long)coins.vout[n].nValue,coins.nLockTime,timestamp,pindex->nTime,(long long)interest);
ret.push_back(Pair("interest", ValueFromAmount(interest)));
Object o; Object o;
ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o, true); ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o, true);
ret.push_back(Pair("scriptPubKey", o)); ret.push_back(Pair("scriptPubKey", o));

View File

@@ -39,6 +39,8 @@ using namespace std;
* *
* Or alternatively, create a specific query method for the information. * Or alternatively, create a specific query method for the information.
**/ **/
uint64_t komodo_interestsum();
Value getinfo(const Array& params, bool fHelp) Value getinfo(const Array& params, bool fHelp)
{ {
extern uint256 NOTARIZED_HASH,NOTARIZED_DESTTXID; extern uint256 NOTARIZED_HASH,NOTARIZED_DESTTXID;
@@ -90,10 +92,13 @@ Value getinfo(const Array& params, bool fHelp)
if (pwalletMain) { if (pwalletMain) {
obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
obj.push_back(Pair("interest", ValueFromAmount(komodo_interestsum())));
} }
#endif #endif
obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("blocks", (int)chainActive.Height()));
obj.push_back(Pair("timeoffset", GetTimeOffset())); obj.push_back(Pair("timeoffset", GetTimeOffset()));
if ( chainActive.Tip() != 0 )
obj.push_back(Pair("tiptime", (int)chainActive.Tip()->nTime));
obj.push_back(Pair("connections", (int)vNodes.size())); obj.push_back(Pair("connections", (int)vNodes.size()));
obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string()))); obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string())));
obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("difficulty", (double)GetDifficulty()));

View File

@@ -122,16 +122,18 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
entry.push_back(Pair("vin", vin)); entry.push_back(Pair("vin", vin));
Array vout; Array vout;
BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
CBlockIndex *pindex = it->second; CBlockIndex *tipindex,*pindex = it->second;
uint64_t interest; uint64_t interest;
for (unsigned int i = 0; i < tx.vout.size(); i++) { for (unsigned int i = 0; i < tx.vout.size(); i++) {
const CTxOut& txout = tx.vout[i]; const CTxOut& txout = tx.vout[i];
Object out; Object out;
out.push_back(Pair("value", ValueFromAmount(txout.nValue))); out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
if ( pindex != 0 && tx.nLockTime != 0 ) if ( pindex != 0 && tx.nLockTime != 0 && (tipindex= chainActive.Tip()) != 0 )
{ {
interest = komodo_interest(pindex->nHeight,txout.nValue,tx.nLockTime,pindex->nTime); extern char ASSETCHAINS_SYMBOL[16];
//fprintf(stderr,"TxtoJSON interest %llu %.8f\n",(long long)interest,(double)interest/COIN); interest = komodo_interest(pindex->nHeight,txout.nValue,tx.nLockTime,tipindex->nTime);
if ( strcmp("REVS",ASSETCHAINS_SYMBOL) == 0 )
fprintf(stderr,"TxtoJSON interest %llu %.8f (%d %llu %u %u)\n",(long long)interest,(double)interest/COIN,(int32_t)pindex->nHeight,(long long)txout.nValue,(uint32_t)tx.nLockTime,(int32_t)tipindex->nTime);
out.push_back(Pair("interest", ValueFromAmount(interest))); out.push_back(Pair("interest", ValueFromAmount(interest)));
} }
out.push_back(Pair("n", (int64_t)i)); out.push_back(Pair("n", (int64_t)i));

View File

@@ -253,7 +253,7 @@ Value help(const Array& params, bool fHelp)
Value stop(const Array& params, bool fHelp) Value stop(const Array& params, bool fHelp)
{ {
// Accept the deprecated and ignored 'detach' boolean argument // Accept the deprecated and ignored 'detach' boolean argument
if (fHelp || params.size() > 1) if (fHelp || params.size() > 1)
throw runtime_error( throw runtime_error(
"stop\n" "stop\n"
@@ -638,7 +638,7 @@ void StartRPCThreads()
"The username and password MUST NOT be the same.\n" "The username and password MUST NOT be the same.\n"
"If the file does not exist, create it with owner-readable-only file permissions.\n" "If the file does not exist, create it with owner-readable-only file permissions.\n"
"It is also recommended to set alertnotify so you are notified of problems;\n" "It is also recommended to set alertnotify so you are notified of problems;\n"
"for example: alertnotify=echo %%s | mail -s \"Zcash Alert\" admin@foo.com\n"), "for example: alertnotify=echo %%s | mail -s \"Komodo Alert\" admin@foo.com\n"),
GetConfigFile().string(), GetConfigFile().string(),
EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32)), EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32)),
"", CClientUIInterface::MSG_ERROR | CClientUIInterface::SECURE); "", CClientUIInterface::MSG_ERROR | CClientUIInterface::SECURE);

View File

@@ -375,7 +375,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet)
std::string testKey = CZCSpendingKey(testSpendingKey).ToString(); std::string testKey = CZCSpendingKey(testSpendingKey).ToString();
// create test data using the random key // create test data using the random key
std::string format_str = "# Wallet dump created by Zcash v0.11.2.0.z8-9155cc6-dirty (2016-08-11 11:37:00 -0700)\n" std::string format_str = "# Wallet dump created by Komodo v0.11.2.0.z8-9155cc6-dirty (2016-08-11 11:37:00 -0700)\n"
"# * Created on 2016-08-12T21:55:36Z\n" "# * Created on 2016-08-12T21:55:36Z\n"
"# * Best block at time of backup was 0 (0de0a3851fef2d433b9b4f51d4342bdd24c5ddd793eb8fba57189f07e9235d52),\n" "# * Best block at time of backup was 0 (0de0a3851fef2d433b9b4f51d4342bdd24c5ddd793eb8fba57189f07e9235d52),\n"
"# mined on 2009-01-03T18:15:05Z\n" "# mined on 2009-01-03T18:15:05Z\n"

View File

@@ -182,7 +182,7 @@ Value importaddress(const Array& params, bool fHelp)
std::vector<unsigned char> data(ParseHex(params[0].get_str())); std::vector<unsigned char> data(ParseHex(params[0].get_str()));
script = CScript(data.begin(), data.end()); script = CScript(data.begin(), data.end());
} else { } else {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address or script"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Komodo address or script");
} }
string strLabel = ""; string strLabel = "";
@@ -408,7 +408,7 @@ Value dumpprivkey(const Array& params, bool fHelp)
string strAddress = params[0].get_str(); string strAddress = params[0].get_str();
CBitcoinAddress address; CBitcoinAddress address;
if (!address.SetString(strAddress)) if (!address.SetString(strAddress))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Komodo address");
CKeyID keyID; CKeyID keyID;
if (!address.GetKeyID(keyID)) if (!address.GetKeyID(keyID))
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key"); throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
@@ -483,7 +483,7 @@ Value dumpwallet_impl(const Array& params, bool fHelp, bool fDumpZKeys)
std::sort(vKeyBirth.begin(), vKeyBirth.end()); std::sort(vKeyBirth.begin(), vKeyBirth.end());
// produce output // produce output
file << strprintf("# Wallet dump created by Zcash %s (%s)\n", CLIENT_BUILD, CLIENT_DATE); file << strprintf("# Wallet dump created by Komodo %s (%s)\n", CLIENT_BUILD, CLIENT_DATE);
file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime())); file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime()));
file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString()); file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString());
file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.Tip()->GetBlockTime())); file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.Tip()->GetBlockTime()));

View File

@@ -72,8 +72,12 @@ void EnsureWalletIsUnlocked()
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
} }
uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue);
uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
void WalletTxToJSON(const CWalletTx& wtx, Object& entry) void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
{ {
//int32_t i,n,txheight; uint32_t locktime; uint64_t interest = 0;
int confirms = wtx.GetDepthInMainChain(); int confirms = wtx.GetDepthInMainChain();
entry.push_back(Pair("confirmations", confirms)); entry.push_back(Pair("confirmations", confirms));
if (wtx.IsCoinBase()) if (wtx.IsCoinBase())
@@ -86,6 +90,11 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
} }
uint256 hash = wtx.GetHash(); uint256 hash = wtx.GetHash();
entry.push_back(Pair("txid", hash.GetHex())); entry.push_back(Pair("txid", hash.GetHex()));
//n = wtx.vout.size();
//for (i=0; i<n; i++)
// interest += komodo_interest(mapBlockIndex[wtx.hashBlock]->nHeight,wtx.vout[i].nValue,wtx.nLockTime,mapBlockIndex[wtx.hashBlock]->nTime);
//entry.push_back(Pair("interest", interest));
Array conflicts; Array conflicts;
BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts()) BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts())
conflicts.push_back(conflict.GetHex()); conflicts.push_back(conflict.GetHex());
@@ -114,7 +123,7 @@ Value getnewaddress(const Array& params, bool fHelp)
if (fHelp || params.size() > 1) if (fHelp || params.size() > 1)
throw runtime_error( throw runtime_error(
"getnewaddress ( \"account\" )\n" "getnewaddress ( \"account\" )\n"
"\nReturns a new Zcash address for receiving payments.\n" "\nReturns a new Komodo address for receiving payments.\n"
"\nArguments:\n" "\nArguments:\n"
"1. \"account\" (string, optional) DEPRECATED. If provided, it MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n" "1. \"account\" (string, optional) DEPRECATED. If provided, it MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
"\nResult:\n" "\nResult:\n"
@@ -191,7 +200,7 @@ Value getaccountaddress(const Array& params, bool fHelp)
if (fHelp || params.size() != 1) if (fHelp || params.size() != 1)
throw runtime_error( throw runtime_error(
"getaccountaddress \"account\"\n" "getaccountaddress \"account\"\n"
"\nDEPRECATED. Returns the current Zcash address for receiving payments to this account.\n" "\nDEPRECATED. Returns the current Komodo address for receiving payments to this account.\n"
"\nArguments:\n" "\nArguments:\n"
"1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n" "1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
"\nResult:\n" "\nResult:\n"
@@ -223,7 +232,7 @@ Value getrawchangeaddress(const Array& params, bool fHelp)
if (fHelp || params.size() > 1) if (fHelp || params.size() > 1)
throw runtime_error( throw runtime_error(
"getrawchangeaddress\n" "getrawchangeaddress\n"
"\nReturns a new Zcash address, for receiving change.\n" "\nReturns a new Komodo address, for receiving change.\n"
"This is for use with raw transactions, NOT normal use.\n" "This is for use with raw transactions, NOT normal use.\n"
"\nResult:\n" "\nResult:\n"
"\"address\" (string) The address\n" "\"address\" (string) The address\n"
@@ -271,7 +280,7 @@ Value setaccount(const Array& params, bool fHelp)
CBitcoinAddress address(params[0].get_str()); CBitcoinAddress address(params[0].get_str());
if (!address.IsValid()) if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Komodo address");
string strAccount; string strAccount;
if (params.size() > 1) if (params.size() > 1)
@@ -318,7 +327,7 @@ Value getaccount(const Array& params, bool fHelp)
CBitcoinAddress address(params[0].get_str()); CBitcoinAddress address(params[0].get_str());
if (!address.IsValid()) if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Komodo address");
string strAccount; string strAccount;
map<CTxDestination, CAddressBookData>::iterator mi = pwalletMain->mapAddressBook.find(address.Get()); map<CTxDestination, CAddressBookData>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
@@ -443,7 +452,7 @@ Value sendtoaddress(const Array& params, bool fHelp)
CBitcoinAddress address(params[0].get_str()); CBitcoinAddress address(params[0].get_str());
if (!address.IsValid()) if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Komodo address");
// Amount // Amount
CAmount nAmount = AmountFromValue(params[1]); CAmount nAmount = AmountFromValue(params[1]);
@@ -683,7 +692,7 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
// Bitcoin address // Bitcoin address
CBitcoinAddress address = CBitcoinAddress(params[0].get_str()); CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
if (!address.IsValid()) if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Komodo address");
CScript scriptPubKey = GetScriptForDestination(address.Get()); CScript scriptPubKey = GetScriptForDestination(address.Get());
if (!IsMine(*pwalletMain,scriptPubKey)) if (!IsMine(*pwalletMain,scriptPubKey))
return (double)0.0; return (double)0.0;
@@ -995,7 +1004,7 @@ Value sendfrom(const Array& params, bool fHelp)
string strAccount = AccountFromValue(params[0]); string strAccount = AccountFromValue(params[0]);
CBitcoinAddress address(params[1].get_str()); CBitcoinAddress address(params[1].get_str());
if (!address.IsValid()) if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Komodo address");
CAmount nAmount = AmountFromValue(params[2]); CAmount nAmount = AmountFromValue(params[2]);
int nMinDepth = 1; int nMinDepth = 1;
if (params.size() > 3) if (params.size() > 3)
@@ -1087,7 +1096,7 @@ Value sendmany(const Array& params, bool fHelp)
{ {
CBitcoinAddress address(s.name_); CBitcoinAddress address(s.name_);
if (!address.IsValid()) if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Zcash address: ")+s.name_); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Komodo address: ")+s.name_);
if (setAddress.count(address)) if (setAddress.count(address))
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_); throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
@@ -1139,7 +1148,7 @@ Value addmultisigaddress(const Array& params, bool fHelp)
{ {
string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n" string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
"\nAdd a nrequired-to-sign multisignature address to the wallet.\n" "\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
"Each key is a Zcash address or hex-encoded public key.\n" "Each key is a Komodo address or hex-encoded public key.\n"
"If 'account' is specified (DEPRECATED), assign address to that account.\n" "If 'account' is specified (DEPRECATED), assign address to that account.\n"
"\nArguments:\n" "\nArguments:\n"
@@ -2134,7 +2143,7 @@ Value encryptwallet(const Array& params, bool fHelp)
// slack space in .dat files; that is bad if the old data is // slack space in .dat files; that is bad if the old data is
// unencrypted private keys. So: // unencrypted private keys. So:
StartShutdown(); StartShutdown();
return "wallet encrypted; Zcash server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup."; return "wallet encrypted; Komodo server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
} }
Value lockunspent(const Array& params, bool fHelp) Value lockunspent(const Array& params, bool fHelp)
@@ -2423,7 +2432,7 @@ Value listunspent(const Array& params, bool fHelp)
BOOST_FOREACH(Value& input, inputs) { BOOST_FOREACH(Value& input, inputs) {
CBitcoinAddress address(input.get_str()); CBitcoinAddress address(input.get_str());
if (!address.IsValid()) if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Zcash address: ")+input.get_str()); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Komodo address: ")+input.get_str());
if (setAddress.count(address)) if (setAddress.count(address))
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str()); throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
setAddress.insert(address); setAddress.insert(address);
@@ -2473,11 +2482,11 @@ Value listunspent(const Array& params, bool fHelp)
if ( out.tx->nLockTime != 0 ) if ( out.tx->nLockTime != 0 )
{ {
BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
CBlockIndex *pindex = it->second; CBlockIndex *tipindex,*pindex = it->second;
uint64_t interest; uint64_t interest;
if ( pindex != 0 ) if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 )
{ {
interest = komodo_interest(pindex->nHeight,nValue,out.tx->nLockTime,pindex->nTime); interest = komodo_interest(pindex->nHeight,nValue,out.tx->nLockTime,tipindex->nTime);
entry.push_back(Pair("interest",ValueFromAmount(interest))); entry.push_back(Pair("interest",ValueFromAmount(interest)));
} }
} }
@@ -2489,6 +2498,30 @@ Value listunspent(const Array& params, bool fHelp)
return results; return results;
} }
uint64_t komodo_interestsum()
{
uint64_t interest,sum = 0;
vector<COutput> vecOutputs;
assert(pwalletMain != NULL);
LOCK2(cs_main, pwalletMain->cs_wallet);
pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
BOOST_FOREACH(const COutput& out,vecOutputs)
{
CAmount nValue = out.tx->vout[out.i].nValue;
if ( out.tx->nLockTime != 0 )
{
BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
CBlockIndex *tipindex,*pindex = it->second;
if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 )
{
interest = komodo_interest(pindex->nHeight,nValue,out.tx->nLockTime,tipindex->nTime);
sum += interest;
}
}
}
return(sum);
}
Value zc_sample_joinsplit(const json_spirit::Array& params, bool fHelp) Value zc_sample_joinsplit(const json_spirit::Array& params, bool fHelp)
{ {
if (fHelp) { if (fHelp) {
@@ -3181,9 +3214,11 @@ Value z_gettotalbalance(const Array& params, bool fHelp)
// so we use our own method to get balance of utxos. // so we use our own method to get balance of utxos.
CAmount nBalance = getBalanceTaddr("", nMinDepth); CAmount nBalance = getBalanceTaddr("", nMinDepth);
CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth); CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth);
CAmount nTotalBalance = nBalance + nPrivateBalance; uint64_t interest = komodo_interestsum();
CAmount nTotalBalance = nBalance + nPrivateBalance + interest;
Object result; Object result;
result.push_back(Pair("transparent", FormatMoney(nBalance, false))); result.push_back(Pair("transparent", FormatMoney(nBalance, false)));
result.push_back(Pair("interest", FormatMoney(interest, false)));
result.push_back(Pair("private", FormatMoney(nPrivateBalance, false))); result.push_back(Pair("private", FormatMoney(nPrivateBalance, false)));
result.push_back(Pair("total", FormatMoney(nTotalBalance, false))); result.push_back(Pair("total", FormatMoney(nTotalBalance, false)));
return result; return result;

View File

@@ -78,24 +78,24 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
empty_wallet(); empty_wallet();
// with an empty wallet we can't even pay one cent // with an empty wallet we can't even pay one cent
BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet,0));
add_coin(1*CENT, 4); // add a new 1 cent coin add_coin(1*CENT, 4); // add a new 1 cent coin
// with a new 1 cent coin, we still can't find a mature 1 cent // with a new 1 cent coin, we still can't find a mature 1 cent
BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet,0));
// but we can find a new 1 cent // but we can find a new 1 cent
BOOST_CHECK( wallet.SelectCoinsMinConf( 1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK( wallet.SelectCoinsMinConf( 1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet,0));
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); BOOST_CHECK_EQUAL(nValueRet, 1 * CENT);
add_coin(2*CENT); // add a mature 2 cent coin add_coin(2*CENT); // add a mature 2 cent coin
// we can't make 3 cents of mature coins // we can't make 3 cents of mature coins
BOOST_CHECK(!wallet.SelectCoinsMinConf( 3 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK(!wallet.SelectCoinsMinConf( 3 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet,0));
// we can make 3 cents of new coins // we can make 3 cents of new coins
BOOST_CHECK( wallet.SelectCoinsMinConf( 3 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK( wallet.SelectCoinsMinConf( 3 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet,0));
BOOST_CHECK_EQUAL(nValueRet, 3 * CENT); BOOST_CHECK_EQUAL(nValueRet, 3 * CENT);
add_coin(5*CENT); // add a mature 5 cent coin, add_coin(5*CENT); // add a mature 5 cent coin,
@@ -105,33 +105,33 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
// now we have new: 1+10=11 (of which 10 was self-sent), and mature: 2+5+20=27. total = 38 // now we have new: 1+10=11 (of which 10 was self-sent), and mature: 2+5+20=27. total = 38
// we can't make 38 cents only if we disallow new coins: // we can't make 38 cents only if we disallow new coins:
BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet,0));
// we can't even make 37 cents if we don't allow new coins even if they're from us // we can't even make 37 cents if we don't allow new coins even if they're from us
BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 6, 6, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 6, 6, vCoins, setCoinsRet, nValueRet,0));
// but we can make 37 cents if we accept new coins from ourself // but we can make 37 cents if we accept new coins from ourself
BOOST_CHECK( wallet.SelectCoinsMinConf(37 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK( wallet.SelectCoinsMinConf(37 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet,0));
BOOST_CHECK_EQUAL(nValueRet, 37 * CENT); BOOST_CHECK_EQUAL(nValueRet, 37 * CENT);
// and we can make 38 cents if we accept all new coins // and we can make 38 cents if we accept all new coins
BOOST_CHECK( wallet.SelectCoinsMinConf(38 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK( wallet.SelectCoinsMinConf(38 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet,0));
BOOST_CHECK_EQUAL(nValueRet, 38 * CENT); BOOST_CHECK_EQUAL(nValueRet, 38 * CENT);
// try making 34 cents from 1,2,5,10,20 - we can't do it exactly // try making 34 cents from 1,2,5,10,20 - we can't do it exactly
BOOST_CHECK( wallet.SelectCoinsMinConf(34 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK( wallet.SelectCoinsMinConf(34 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet,0));
BOOST_CHECK_GT(nValueRet, 34 * CENT); // but should get more than 34 cents BOOST_CHECK_GT(nValueRet, 34 * CENT); // but should get more than 34 cents
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); // the best should be 20+10+5. it's incredibly unlikely the 1 or 2 got included (but possible) BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); // the best should be 20+10+5. it's incredibly unlikely the 1 or 2 got included (but possible)
// when we try making 7 cents, the smaller coins (1,2,5) are enough. We should see just 2+5 // when we try making 7 cents, the smaller coins (1,2,5) are enough. We should see just 2+5
BOOST_CHECK( wallet.SelectCoinsMinConf( 7 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK( wallet.SelectCoinsMinConf( 7 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet,0));
BOOST_CHECK_EQUAL(nValueRet, 7 * CENT); BOOST_CHECK_EQUAL(nValueRet, 7 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
// when we try making 8 cents, the smaller coins (1,2,5) are exactly enough. // when we try making 8 cents, the smaller coins (1,2,5) are exactly enough.
BOOST_CHECK( wallet.SelectCoinsMinConf( 8 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK( wallet.SelectCoinsMinConf( 8 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet,0));
BOOST_CHECK(nValueRet == 8 * CENT); BOOST_CHECK(nValueRet == 8 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
// when we try making 9 cents, no subset of smaller coins is enough, and we get the next bigger coin (10) // when we try making 9 cents, no subset of smaller coins is enough, and we get the next bigger coin (10)
BOOST_CHECK( wallet.SelectCoinsMinConf( 9 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK( wallet.SelectCoinsMinConf( 9 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet,0));
BOOST_CHECK_EQUAL(nValueRet, 10 * CENT); BOOST_CHECK_EQUAL(nValueRet, 10 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
@@ -145,30 +145,30 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
add_coin(30*CENT); // now we have 6+7+8+20+30 = 71 cents total add_coin(30*CENT); // now we have 6+7+8+20+30 = 71 cents total
// check that we have 71 and not 72 // check that we have 71 and not 72
BOOST_CHECK( wallet.SelectCoinsMinConf(71 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK( wallet.SelectCoinsMinConf(71 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet,0));
BOOST_CHECK(!wallet.SelectCoinsMinConf(72 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK(!wallet.SelectCoinsMinConf(72 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet,0));
// now try making 16 cents. the best smaller coins can do is 6+7+8 = 21; not as good at the next biggest coin, 20 // now try making 16 cents. the best smaller coins can do is 6+7+8 = 21; not as good at the next biggest coin, 20
BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet,0));
BOOST_CHECK_EQUAL(nValueRet, 20 * CENT); // we should get 20 in one coin BOOST_CHECK_EQUAL(nValueRet, 20 * CENT); // we should get 20 in one coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
add_coin( 5*CENT); // now we have 5+6+7+8+20+30 = 75 cents total add_coin( 5*CENT); // now we have 5+6+7+8+20+30 = 75 cents total
// now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, better than the next biggest coin, 20 // now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, better than the next biggest coin, 20
BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet,0));
BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 3 coins BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 3 coins
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
add_coin( 18*CENT); // now we have 5+6+7+8+18+20+30 add_coin( 18*CENT); // now we have 5+6+7+8+18+20+30
// and now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, the same as the next biggest coin, 18 // and now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, the same as the next biggest coin, 18
BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet,0));
BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 1 coin BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 1 coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); // because in the event of a tie, the biggest coin wins BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); // because in the event of a tie, the biggest coin wins
// now try making 11 cents. we should get 5+6 // now try making 11 cents. we should get 5+6
BOOST_CHECK( wallet.SelectCoinsMinConf(11 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK( wallet.SelectCoinsMinConf(11 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet,0));
BOOST_CHECK_EQUAL(nValueRet, 11 * CENT); BOOST_CHECK_EQUAL(nValueRet, 11 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
@@ -177,11 +177,11 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
add_coin( 2*COIN); add_coin( 2*COIN);
add_coin( 3*COIN); add_coin( 3*COIN);
add_coin( 4*COIN); // now we have 5+6+7+8+18+20+30+100+200+300+400 = 1094 cents add_coin( 4*COIN); // now we have 5+6+7+8+18+20+30+100+200+300+400 = 1094 cents
BOOST_CHECK( wallet.SelectCoinsMinConf(95 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK( wallet.SelectCoinsMinConf(95 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet,0));
BOOST_CHECK_EQUAL(nValueRet, 1 * COIN); // we should get 1 BTC in 1 coin BOOST_CHECK_EQUAL(nValueRet, 1 * COIN); // we should get 1 BTC in 1 coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
BOOST_CHECK( wallet.SelectCoinsMinConf(195 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK( wallet.SelectCoinsMinConf(195 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet,0));
BOOST_CHECK_EQUAL(nValueRet, 2 * COIN); // we should get 2 BTC in 1 coin BOOST_CHECK_EQUAL(nValueRet, 2 * COIN); // we should get 2 BTC in 1 coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
@@ -195,14 +195,14 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
// try making 1 cent from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 = 1.5 cents // try making 1 cent from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 = 1.5 cents
// we'll get sub-cent change whatever happens, so can expect 1.0 exactly // we'll get sub-cent change whatever happens, so can expect 1.0 exactly
BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet,0));
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); BOOST_CHECK_EQUAL(nValueRet, 1 * CENT);
// but if we add a bigger coin, making it possible to avoid sub-cent change, things change: // but if we add a bigger coin, making it possible to avoid sub-cent change, things change:
add_coin(1111*CENT); add_coin(1111*CENT);
// try making 1 cent from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5 cents // try making 1 cent from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5 cents
BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet,0));
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount
// if we add more sub-cent coins: // if we add more sub-cent coins:
@@ -210,7 +210,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
add_coin(0.7*CENT); add_coin(0.7*CENT);
// and try again to make 1.0 cents, we can still make 1.0 cents // and try again to make 1.0 cents, we can still make 1.0 cents
BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet,0));
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount
// run the 'mtgox' test (see http://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf) // run the 'mtgox' test (see http://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf)
@@ -219,7 +219,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
for (int i = 0; i < 20; i++) for (int i = 0; i < 20; i++)
add_coin(50000 * COIN); add_coin(50000 * COIN);
BOOST_CHECK( wallet.SelectCoinsMinConf(500000 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK( wallet.SelectCoinsMinConf(500000 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet,0));
BOOST_CHECK_EQUAL(nValueRet, 500000 * COIN); // we should get the exact amount BOOST_CHECK_EQUAL(nValueRet, 500000 * COIN); // we should get the exact amount
BOOST_CHECK_EQUAL(setCoinsRet.size(), 10U); // in ten coins BOOST_CHECK_EQUAL(setCoinsRet.size(), 10U); // in ten coins
@@ -232,7 +232,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
add_coin(0.6 * CENT); add_coin(0.6 * CENT);
add_coin(0.7 * CENT); add_coin(0.7 * CENT);
add_coin(1111 * CENT); add_coin(1111 * CENT);
BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet,0));
BOOST_CHECK_EQUAL(nValueRet, 1111 * CENT); // we get the bigger coin BOOST_CHECK_EQUAL(nValueRet, 1111 * CENT); // we get the bigger coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
@@ -242,7 +242,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
add_coin(0.6 * CENT); add_coin(0.6 * CENT);
add_coin(0.8 * CENT); add_coin(0.8 * CENT);
add_coin(1111 * CENT); add_coin(1111 * CENT);
BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet,0));
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); // in two coins 0.4+0.6 BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); // in two coins 0.4+0.6
@@ -253,12 +253,12 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
add_coin(1 * COIN); add_coin(1 * COIN);
// trying to make 1.0001 from these three coins // trying to make 1.0001 from these three coins
BOOST_CHECK( wallet.SelectCoinsMinConf(1.0001 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK( wallet.SelectCoinsMinConf(1.0001 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet,0));
BOOST_CHECK_EQUAL(nValueRet, 1.0105 * COIN); // we should get all coins BOOST_CHECK_EQUAL(nValueRet, 1.0105 * COIN); // we should get all coins
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
// but if we try to make 0.999, we should take the bigger of the two small coins to avoid sub-cent change // but if we try to make 0.999, we should take the bigger of the two small coins to avoid sub-cent change
BOOST_CHECK( wallet.SelectCoinsMinConf(0.999 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK( wallet.SelectCoinsMinConf(0.999 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet,0));
BOOST_CHECK_EQUAL(nValueRet, 1.01 * COIN); // we should get 1 + 0.01 BOOST_CHECK_EQUAL(nValueRet, 1.01 * COIN); // we should get 1 + 0.01
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
@@ -270,8 +270,8 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
// picking 50 from 100 coins doesn't depend on the shuffle, // picking 50 from 100 coins doesn't depend on the shuffle,
// but does depend on randomness in the stochastic approximation code // but does depend on randomness in the stochastic approximation code
BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, vCoins, setCoinsRet , nValueRet)); BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, vCoins, setCoinsRet , nValueRet,0));
BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, vCoins, setCoinsRet2, nValueRet)); BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, vCoins, setCoinsRet2, nValueRet,0));
BOOST_CHECK(!equal_sets(setCoinsRet, setCoinsRet2)); BOOST_CHECK(!equal_sets(setCoinsRet, setCoinsRet2));
int fails = 0; int fails = 0;
@@ -279,8 +279,8 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
{ {
// selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time // selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time
// run the test RANDOM_REPEATS times and only complain if all of them fail // run the test RANDOM_REPEATS times and only complain if all of them fail
BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, vCoins, setCoinsRet , nValueRet)); BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, vCoins, setCoinsRet , nValueRet,0));
BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, vCoins, setCoinsRet2, nValueRet)); BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, vCoins, setCoinsRet2, nValueRet,0));
if (equal_sets(setCoinsRet, setCoinsRet2)) if (equal_sets(setCoinsRet, setCoinsRet2))
fails++; fails++;
} }
@@ -296,8 +296,8 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
{ {
// selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time // selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time
// run the test RANDOM_REPEATS times and only complain if all of them fail // run the test RANDOM_REPEATS times and only complain if all of them fail
BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, vCoins, setCoinsRet , nValueRet)); BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, vCoins, setCoinsRet , nValueRet,0));
BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, vCoins, setCoinsRet2, nValueRet)); BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, vCoins, setCoinsRet2, nValueRet,0));
if (equal_sets(setCoinsRet, setCoinsRet2)) if (equal_sets(setCoinsRet, setCoinsRet2))
fails++; fails++;
} }

View File

@@ -2169,8 +2169,11 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const
/** /**
* populate vCoins with vector of available COutputs. * populate vCoins with vector of available COutputs.
*/ */
uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeZeroValue, bool fIncludeCoinBase) const void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeZeroValue, bool fIncludeCoinBase) const
{ {
uint64_t interest,*ptr;
vCoins.clear(); vCoins.clear();
{ {
@@ -2196,19 +2199,56 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
if (nDepth < 0) if (nDepth < 0)
continue; continue;
for (unsigned int i = 0; i < pcoin->vout.size(); i++) { for (unsigned int i = 0; i < pcoin->vout.size(); i++)
{
isminetype mine = IsMine(pcoin->vout[i]); isminetype mine = IsMine(pcoin->vout[i]);
if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO && if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO &&
!IsLockedCoin((*it).first, i) && (pcoin->vout[i].nValue > 0 || fIncludeZeroValue) && !IsLockedCoin((*it).first, i) && (pcoin->vout[i].nValue > 0 || fIncludeZeroValue) &&
(!coinControl || !coinControl->HasSelected() || coinControl->IsSelected((*it).first, i))) (!coinControl || !coinControl->HasSelected() || coinControl->IsSelected((*it).first, i)))
vCoins.push_back(COutput(pcoin, i, nDepth, (mine & ISMINE_SPENDABLE) != ISMINE_NO)); {
#ifdef KOMODO_ENABLE_INTEREST
extern char ASSETCHAINS_SYMBOL[16];
if ( ASSETCHAINS_SYMBOL[0] == 0 && chainActive.Tip() != 0 && chainActive.Tip()->nHeight >= 60000 )
{
if ( pcoin->vout[i].nValue >= 10*COIN )
{
interest = komodo_interest(chainActive.Tip()->nHeight+1,pcoin->vout[i].nValue,pcoin->nLockTime,chainActive.Tip()->nTime);
if ( interest != 0 )
{
//printf("wallet nValueRet %.8f += interest %.8f ht.%d lock.%u tip.%u\n",(double)pcoin->vout[i].nValue/COIN,(double)interest/COIN,chainActive.Tip()->nHeight+1,pcoin->nLockTime,chainActive.Tip()->nTime);
//fprintf(stderr,"wallet nValueRet %.8f += interest %.8f ht.%d lock.%u tip.%u\n",(double)pcoin->vout[i].nValue/COIN,(double)interest/COIN,chainActive.Tip()->nHeight+1,pcoin->nLockTime,chainActive.Tip()->nTime);
//ptr = (uint64_t *)&pcoin->vout[i].nValue;
//(*ptr) += interest;
ptr = (uint64_t *)&pcoin->vout[i].interest;
(*ptr) = interest;
//pcoin->vout[i].nValue += interest;
}
else
{
ptr = (uint64_t *)&pcoin->vout[i].interest;
(*ptr) = 0;
}
}
else
{
ptr = (uint64_t *)&pcoin->vout[i].interest;
(*ptr) = 0;
}
}
else
{
ptr = (uint64_t *)&pcoin->vout[i].interest;
(*ptr) = 0;
}
#endif
vCoins.push_back(COutput(pcoin, i, nDepth, (mine & ISMINE_SPENDABLE) != ISMINE_NO));
}
} }
} }
} }
} }
static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,unsigned int> > >vValue, const CAmount& nTotalLower, const CAmount& nTargetValue, static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,unsigned int> > >vValue, const CAmount& nTotalLower, const CAmount& nTargetValue,vector<char>& vfBest, CAmount& nBest, int iterations = 1000)
vector<char>& vfBest, CAmount& nBest, int iterations = 1000)
{ {
vector<char> vfIncluded; vector<char> vfIncluded;
@@ -2253,12 +2293,13 @@ static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,uns
} }
} }
bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, vector<COutput> vCoins, bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, vector<COutput> vCoins,set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, uint64_t *interestp) const
set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const
{ {
uint64_t interests[512],lowest_interest = 0; int32_t count = 0;
setCoinsRet.clear(); setCoinsRet.clear();
memset(interests,0,sizeof(interests));
nValueRet = 0; nValueRet = 0;
*interestp = 0;
// List of values less than target // List of values less than target
pair<CAmount, pair<const CWalletTx*,unsigned int> > coinLowestLarger; pair<CAmount, pair<const CWalletTx*,unsigned int> > coinLowestLarger;
coinLowestLarger.first = std::numeric_limits<CAmount>::max(); coinLowestLarger.first = std::numeric_limits<CAmount>::max();
@@ -2287,16 +2328,23 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int
{ {
setCoinsRet.insert(coin.second); setCoinsRet.insert(coin.second);
nValueRet += coin.first; nValueRet += coin.first;
*interestp += pcoin->vout[i].interest;
return true; return true;
} }
else if (n < nTargetValue + CENT) else if (n < nTargetValue + CENT)
{ {
vValue.push_back(coin); vValue.push_back(coin);
nTotalLower += n; nTotalLower += n;
if ( count < sizeof(interests)/sizeof(*interests) )
{
//fprintf(stderr,"count.%d %.8f\n",count,(double)pcoin->vout[i].interest/COIN);
interests[count++] = pcoin->vout[i].interest;
}
} }
else if (n < coinLowestLarger.first) else if (n < coinLowestLarger.first)
{ {
coinLowestLarger = coin; coinLowestLarger = coin;
lowest_interest = pcoin->vout[i].interest;
} }
} }
@@ -2306,6 +2354,8 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int
{ {
setCoinsRet.insert(vValue[i].second); setCoinsRet.insert(vValue[i].second);
nValueRet += vValue[i].first; nValueRet += vValue[i].first;
if ( i < count )
*interestp += interests[i];
} }
return true; return true;
} }
@@ -2316,6 +2366,7 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int
return false; return false;
setCoinsRet.insert(coinLowestLarger.second); setCoinsRet.insert(coinLowestLarger.second);
nValueRet += coinLowestLarger.first; nValueRet += coinLowestLarger.first;
*interestp += lowest_interest;
return true; return true;
} }
@@ -2335,6 +2386,7 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int
{ {
setCoinsRet.insert(coinLowestLarger.second); setCoinsRet.insert(coinLowestLarger.second);
nValueRet += coinLowestLarger.first; nValueRet += coinLowestLarger.first;
*interestp += lowest_interest;
} }
else { else {
for (unsigned int i = 0; i < vValue.size(); i++) for (unsigned int i = 0; i < vValue.size(); i++)
@@ -2342,6 +2394,8 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int
{ {
setCoinsRet.insert(vValue[i].second); setCoinsRet.insert(vValue[i].second);
nValueRet += vValue[i].first; nValueRet += vValue[i].first;
if ( i < count )
*interestp += interests[i];
} }
LogPrint("selectcoins", "SelectCoins() best subset: "); LogPrint("selectcoins", "SelectCoins() best subset: ");
@@ -2354,11 +2408,13 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int
return true; return true;
} }
uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime); bool CWallet::SelectCoins(const CAmount& nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, bool& fOnlyCoinbaseCoinsRet, bool& fNeedCoinbaseCoinsRet, const CCoinControl* coinControl,uint64_t *interestp) const
bool CWallet::SelectCoins(const CAmount& nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, bool& fOnlyCoinbaseCoinsRet, bool& fNeedCoinbaseCoinsRet, const CCoinControl* coinControl) const
{ {
// Output parameter fOnlyCoinbaseCoinsRet is set to true when the only available coins are coinbase utxos. // Output parameter fOnlyCoinbaseCoinsRet is set to true when the only available coins are coinbase utxos.
uint64_t tmp;
if ( interestp == 0 )
interestp = &tmp;
*interestp = 0;
vector<COutput> vCoinsNoCoinbase, vCoinsWithCoinbase; vector<COutput> vCoinsNoCoinbase, vCoinsWithCoinbase;
AvailableCoins(vCoinsNoCoinbase, true, coinControl, false, false); AvailableCoins(vCoinsNoCoinbase, true, coinControl, false, false);
AvailableCoins(vCoinsWithCoinbase, true, coinControl, false, true); AvailableCoins(vCoinsWithCoinbase, true, coinControl, false, true);
@@ -2388,44 +2444,30 @@ bool CWallet::SelectCoins(const CAmount& nTargetValue, set<pair<const CWalletTx*
fNeedCoinbaseCoinsRet = (valueWithCoinbase >= nTargetValue); fNeedCoinbaseCoinsRet = (valueWithCoinbase >= nTargetValue);
} }
} }
// coin control -> return all selected outputs (we want all to go into the transaction for sure)
// coin control -> return all selected outputs (we want all selected to go into the transaction for sure) *interestp = 0;
if (coinControl && coinControl->HasSelected()) if (coinControl && coinControl->HasSelected())
{ {
extern char ASSETCHAINS_SYMBOL[16];
uint64_t interest;
BOOST_FOREACH(const COutput& out, vCoins) BOOST_FOREACH(const COutput& out, vCoins)
{ {
if(!out.fSpendable) if(!out.fSpendable)
continue; continue;
nValueRet += out.tx->vout[out.i].nValue; nValueRet += out.tx->vout[out.i].nValue;
interest = komodo_interest(chainActive.Tip()->nHeight+1,out.tx->vout[out.i].nValue,out.tx->nLockTime,chainActive.Tip()->nTime); *interestp += out.tx->vout[out.i].interest;
#ifdef KOMODO_ENABLE_INTEREST
if ( ASSETCHAINS_SYMBOL[0] == 0 && chainActive.Tip()->nHeight+1 >= 60000 )
{
if ( interest != 0 )
{
printf("nValueRet %.8f += interest %.8f ht.%d lock.%u tip.%u\n",(double)nValueRet/COIN,(double)interest/COIN,chainActive.Tip()->nHeight+1,out.tx->nLockTime,chainActive.Tip()->nTime);
fprintf(stderr,"nValueRet %.8f += interest %.8f ht.%d lock.%u tip.%u\n",(double)nValueRet/COIN,(double)interest/COIN,chainActive.Tip()->nHeight+1,out.tx->nLockTime,chainActive.Tip()->nTime);
}
nValueRet += interest;
}
#endif
setCoinsRet.insert(make_pair(out.tx, out.i)); setCoinsRet.insert(make_pair(out.tx, out.i));
} }
return (nValueRet >= nTargetValue); return (nValueRet >= nTargetValue);
} }
//fprintf(stderr,"nValueRet %8f vs target %.8f\n",(double)nValueRet/COIN,(double)nTargetValue/COIN);
return (SelectCoinsMinConf(nTargetValue, 1, 6, vCoins, setCoinsRet, nValueRet) || return (SelectCoinsMinConf(nTargetValue, 1, 6, vCoins, setCoinsRet, nValueRet,interestp) ||
SelectCoinsMinConf(nTargetValue, 1, 1, vCoins, setCoinsRet, nValueRet) || SelectCoinsMinConf(nTargetValue, 1, 1, vCoins, setCoinsRet, nValueRet,interestp) ||
(bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue, 0, 1, vCoins, setCoinsRet, nValueRet))); (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue, 0, 1, vCoins, setCoinsRet, nValueRet,interestp)));
} }
bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend,
CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosRet, std::string& strFailReason, const CCoinControl* coinControl) CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosRet, std::string& strFailReason, const CCoinControl* coinControl)
{ {
CAmount nValue = 0; uint64_t interest2,interest = 0; CAmount nValue = 0; unsigned int nSubtractFeeFromAmount = 0;
unsigned int nSubtractFeeFromAmount = 0;
BOOST_FOREACH (const CRecipient& recipient, vecSend) BOOST_FOREACH (const CRecipient& recipient, vecSend)
{ {
if (nValue < 0 || recipient.nAmount < 0) if (nValue < 0 || recipient.nAmount < 0)
@@ -2530,7 +2572,8 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend,
CAmount nValueIn = 0; CAmount nValueIn = 0;
bool fOnlyCoinbaseCoins = false; bool fOnlyCoinbaseCoins = false;
bool fNeedCoinbaseCoins = false; bool fNeedCoinbaseCoins = false;
if (!SelectCoins(nTotalValue, setCoins, nValueIn, fOnlyCoinbaseCoins, fNeedCoinbaseCoins, coinControl)) interest = interest2 = 0;
if (!SelectCoins(nTotalValue, setCoins, nValueIn, fOnlyCoinbaseCoins, fNeedCoinbaseCoins, coinControl,&interest))
{ {
if (fOnlyCoinbaseCoins && Params().GetConsensus().fCoinbaseMustBeProtected) { if (fOnlyCoinbaseCoins && Params().GetConsensus().fCoinbaseMustBeProtected) {
strFailReason = _("Coinbase funds can only be sent to a zaddr"); strFailReason = _("Coinbase funds can only be sent to a zaddr");
@@ -2548,13 +2591,16 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend,
//reflecting an assumption the user would accept a bit more delay for //reflecting an assumption the user would accept a bit more delay for
//a chance at a free transaction. //a chance at a free transaction.
//But mempool inputs might still be in the mempool, so their age stays 0 //But mempool inputs might still be in the mempool, so their age stays 0
//fprintf(stderr,"nCredit %.8f interest %.8f\n",(double)nCredit/COIN,(double)pcoin.first->vout[pcoin.second].interest/COIN);
interest2 += pcoin.first->vout[pcoin.second].interest;
int age = pcoin.first->GetDepthInMainChain(); int age = pcoin.first->GetDepthInMainChain();
if (age != 0) if (age != 0)
age += 1; age += 1;
dPriority += (double)nCredit * age; dPriority += (double)nCredit * age;
} }
//fprintf(stderr,"interest sum %.8f, interest2 %.8f\n",(double)interest/COIN,(double)interest2/COIN);
CAmount nChange = nValueIn - nValue; CAmount nChange = (nValueIn - nValue + interest);
//fprintf(stderr,"wallet change %.8f (%.8f - %.8f) interest %.8f total %.8f\n",(double)nChange/COIN,(double)nValueIn/COIN,(double)nValue/COIN,(double)interest/COIN,(double)nTotalValue/COIN);
if (nSubtractFeeFromAmount == 0) if (nSubtractFeeFromAmount == 0)
nChange -= nFeeRet; nChange -= nFeeRet;

View File

@@ -575,7 +575,7 @@ public:
class CWallet : public CCryptoKeyStore, public CValidationInterface class CWallet : public CCryptoKeyStore, public CValidationInterface
{ {
private: private:
bool SelectCoins(const CAmount& nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, bool& fOnlyCoinbaseCoinsRet, bool& fNeedCoinbaseCoinsRet, const CCoinControl *coinControl = NULL) const; bool SelectCoins(const CAmount& nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, bool& fOnlyCoinbaseCoinsRet, bool& fNeedCoinbaseCoinsRet, const CCoinControl *coinControl = NULL,uint64_t *interestp = NULL) const;
CWalletDB *pwalletdbEncryption; CWalletDB *pwalletdbEncryption;
@@ -791,7 +791,7 @@ public:
bool CanSupportFeature(enum WalletFeature wf) { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; } bool CanSupportFeature(enum WalletFeature wf) { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; }
void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL, bool fIncludeZeroValue=false, bool fIncludeCoinBase=true) const; void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL, bool fIncludeZeroValue=false, bool fIncludeCoinBase=true) const;
bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const; bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet,uint64_t *interestp) const;
bool IsSpent(const uint256& hash, unsigned int n) const; bool IsSpent(const uint256& hash, unsigned int n) const;
bool IsSpent(const uint256& nullifier) const; bool IsSpent(const uint256& nullifier) const;