Having a slight issue with this create coin method. I'm getting a few bugs and I'm sort of lost.
When I'm verifying a stealth address private key it works fine, when I print it before sending rewards to it displays just fine, but when I send it the rewards, they go to a pub address. Can anyone spot the bug?
bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int64_t nSearchInterval, int64_t nFees, CTransaction& txNew, CKey& key)
{
CBlockIndex* pindexPrev = pindexBest;
CBigNum bnTargetPerCoinDay;
bnTargetPerCoinDay.SetCompact(nBits);
txNew.vin.clear();
txNew.vout.clear();
// Mark coin stake transaction
CScript scriptEmpty;
scriptEmpty.clear();
txNew.vout.push_back(CTxOut(0, scriptEmpty));
// Choose coins to use
int64_t nBalance = GetBalance();
if (nBalance <= nReserveBalance)
return false;
vector<const CWalletTx*> vwtxPrev;
set<pair<const CWalletTx*,unsigned int> > setCoins;
int64_t nValueIn = 0;
// Select coins with suitable depth
if (!SelectCoinsSimple(nBalance - nReserveBalance, txNew.nTime, nCoinbaseMaturity + 10, setCoins, nValueIn))
return false;
if (setCoins.empty())
return false;
int64_t nCredit = 0;
CScript scriptPubKeyKernel;
CTxDB txdb("r");
BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
{
CTxIndex txindex;
{
LOCK2(cs_main, cs_wallet);
if (!txdb.ReadTxIndex(pcoin.first->GetHash(), txindex))
continue;
}
// Read block header
CBlock block;
{
LOCK2(cs_main, cs_wallet);
if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false))
continue;
}
static int nMaxStakeSearchInterval = 60;
if (block.GetBlockTime() + nStakeMinAge > txNew.nTime - nMaxStakeSearchInterval)
continue; // only count coins meeting min age requirement
bool fKernelFound = false;
for (unsigned int n=0; n<min(nSearchInterval,(int64_t)nMaxStakeSearchInterval) && !fKernelFound && !fShutdown && pindexPrev == pindexBest; n++)
{
// Search backward in time from the given txNew timestamp
// Search nSearchInterval seconds back up to nMaxStakeSearchInterval
uint256 hashProofOfStake = 0, targetProofOfStake = 0;
COutPoint prevoutStake = COutPoint(pcoin.first->GetHash(), pcoin.second);
if (CheckStakeKernelHash(nBits, block, txindex.pos.nTxPos - txindex.pos.nBlockPos, *pcoin.first, prevoutStake, txNew.nTime - n, hashProofOfStake, targetProofOfStake))
{
// Found a kernel
if (fDebug && GetBoolArg("-printcoinstake"))
printf("CreateCoinStake : kernel found\n");
vector<valtype> vSolutions;
txnouttype whichType;
CScript scriptPubKeyOut;
scriptPubKeyKernel = pcoin.first->vout[pcoin.second].scriptPubKey;
if (!Solver(scriptPubKeyKernel, whichType, vSolutions))
{
if (fDebug && GetBoolArg("-printcoinstake"))
printf("CreateCoinStake : failed to parse kernel\n");
break;
}
if (fDebug && GetBoolArg("-printcoinstake"))
printf("CreateCoinStake : parsed kernel type=%d\n", whichType);
if (whichType != TX_PUBKEY && whichType != TX_PUBKEYHASH || whichType != TX_SCRIPTHASH)
{
if (fDebug && GetBoolArg("-printcoinstake"))
printf("CreateCoinStake : no support for kernel type=%d\n", whichType);
break; // only support pay to public key, stealth key and pay to address
}
if(whichType == TX_SCRIPTHASH){//pay to stealth type if exist
// std::set<CStealthAddress>::iterator it;
// for (it = stealthAddresses.begin(); it != stealthAddresses.end(); ++it){
// if(!keystore.GetCScript(stealthAddresses.begin()->Encoded(), key)){
// if (fDebug && GetBoolArg("-printcoinstake"))
// printf("CreateCoinStake : failed to get key for kernel type=%d\n", whichType);
// break; // unable to find hash of the first stealth address
// }
// }
return true;
} else {//no stealth address found pay to
if (whichType == TX_PUBKEYHASH) // pay to address type
{
// convert to pay to public key type
if (!keystore.GetKey(uint160(vSolutions[0]), key))
{
if (fDebug && GetBoolArg("-printcoinstake"))
printf("CreateCoinStake : failed to get key for kernel type=%d\n", whichType);
break; // unable to find corresponding public key
}
scriptPubKeyOut << key.GetPubKey() << OP_CHECKSIG;
}
if (whichType == TX_PUBKEY)
{
valtype& vchPubKey = vSolutions[0];
if (!keystore.GetKey(Hash160(vchPubKey), key))
{
if (fDebug && GetBoolArg("-printcoinstake"))
printf("CreateCoinStake : failed to get key for kernel type=%d\n", whichType);
break; // unable to find corresponding public key
}
if (key.GetPubKey() != vchPubKey)
{
if (fDebug && GetBoolArg("-printcoinstake"))
printf("CreateCoinStake : invalid key for kernel type=%d\n", whichType);
break; // keys mismatch
}
scriptPubKeyOut = scriptPubKeyKernel;
}
}
txNew.nTime -= n;
txNew.vin.push_back(CTxIn(pcoin.first->GetHash(), pcoin.second));
nCredit += pcoin.first->vout[pcoin.second].nValue;
vwtxPrev.push_back(pcoin.first);
txNew.vout.push_back(CTxOut(0, scriptPubKeyOut));
if (GetWeight(block.GetBlockTime(), (int64_t)txNew.nTime) < nStakeSplitAge)
txNew.vout.push_back(CTxOut(0, scriptPubKeyOut)); //split stake
if (fDebug && GetBoolArg("-printcoinstake"))
printf("CreateCoinStake : added kernel type=%d\n", whichType);
fKernelFound = true;
break;
}
}
if (fKernelFound || fShutdown)
break; // if kernel is found stop searching
}
if (nCredit == 0 || nCredit > nBalance - nReserveBalance)
return false;
BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
{
// Attempt to add more inputs
// Only add coins of the same key/address as kernel
if (txNew.vout.size() == 2 && ((pcoin.first->vout[pcoin.second].scriptPubKey == scriptPubKeyKernel || pcoin.first->vout[pcoin.second].scriptPubKey == txNew.vout[1].scriptPubKey))
&& pcoin.first->GetHash() != txNew.vin[0].prevout.hash)
{
int64_t nTimeWeight = GetWeight((int64_t)pcoin.first->nTime, (int64_t)txNew.nTime);
// Stop adding more inputs if already too many inputs
if (txNew.vin.size() >= 100)
break;
// Stop adding more inputs if value is already pretty significant
if (nCredit >= nStakeCombineThreshold)
break;
// Stop adding inputs if reached reserve limit
if (nCredit + pcoin.first->vout[pcoin.second].nValue > nBalance - nReserveBalance)
break;
// Do not add additional significant input
if (pcoin.first->vout[pcoin.second].nValue >= nStakeCombineThreshold)
continue;
// Do not add input that is still too young
if (nTimeWeight < nStakeMinAge)
continue;
txNew.vin.push_back(CTxIn(pcoin.first->GetHash(), pcoin.second));
nCredit += pcoin.first->vout[pcoin.second].nValue;
vwtxPrev.push_back(pcoin.first);
}
}
// Calculate coin age reward
{
uint64_t nCoinAge;
CTxDB txdb("r");
if (!txNew.GetCoinAge(txdb, nCoinAge))
return error("CreateCoinStake : failed to calculate coin age");
int64_t nReward = GetProofOfStakeReward(nCoinAge, pindexBest);
if (nReward <= 0)
return false;
nCredit += nReward;
}
// Set output amount
if (txNew.vout.size() == 3)
{
txNew.vout[1].nValue = (nCredit / 2 / CENT) * CENT;
txNew.vout[2].nValue = nCredit - txNew.vout[1].nValue;
}
else
txNew.vout[1].nValue = nCredit;
// Sign
int nIn = 0;
BOOST_FOREACH(const CWalletTx* pcoin, vwtxPrev)
{
if (!SignSignature(*this, *pcoin, txNew, nIn++))
return error("CreateCoinStake : failed to sign coinstake");
}
// Limit size
unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION);
if (nBytes >= MAX_BLOCK_SIZE_GEN/5)
return error("CreateCoinStake : exceeded coinstake size limit");
// Successfully generated coinstake
return true;
}