Skip to content

Commit

Permalink
Try to stake shield notes
Browse files Browse the repository at this point in the history
  • Loading branch information
panleone committed Apr 8, 2023
1 parent a73c70d commit 7277289
Show file tree
Hide file tree
Showing 11 changed files with 137 additions and 72 deletions.
36 changes: 18 additions & 18 deletions src/blockassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "policy/policy.h"
#include "pow.h"
#include "primitives/transaction.h"
#include "sapling/saplingscriptpubkeyman.h"
#include "spork.h"
#include "timedata.h"
#include "util/system.h"
Expand Down Expand Up @@ -66,8 +67,7 @@ static CMutableTransaction NewCoinbase(const int nHeight, const CScript* pScript
return txCoinbase;
}

bool SolveProofOfStake(CBlock* pblock, CBlockIndex* pindexPrev, CWallet* pwallet,
std::vector<CStakeableOutput>* availableCoins, bool stopPoSOnNewBlock)
bool SolveProofOfStake(CBlock* pblock, CBlockIndex* pindexPrev, CWallet* pwallet, std::vector<CStakeableOutput>* availableCoins, std::vector<CStakeableShieldNote>* availableShieldNotes, bool stopPoSOnNewBlock)
{
boost::this_thread::interruption_point();

Expand All @@ -80,12 +80,12 @@ bool SolveProofOfStake(CBlock* pblock, CBlockIndex* pindexPrev, CWallet* pwallet
CMutableTransaction txCoinStake;
int64_t nTxNewTime = 0;
if (!pwallet->CreateCoinStake(pindexPrev,
pblock->nBits,
txCoinStake,
nTxNewTime,
availableCoins,
stopPoSOnNewBlock
)) {
pblock->nBits,
txCoinStake,
nTxNewTime,
availableCoins,
availableShieldNotes,
stopPoSOnNewBlock)) {
LogPrint(BCLog::STAKING, "%s : stake not found\n", __func__);
return false;
}
Expand Down Expand Up @@ -156,14 +156,15 @@ void BlockAssembler::resetBlock()
}

std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn,
CWallet* pwallet,
bool fProofOfStake,
std::vector<CStakeableOutput>* availableCoins,
bool fNoMempoolTx,
bool fTestValidity,
CBlockIndex* prevBlock,
bool stopPoSOnNewBlock,
bool fIncludeQfc)
CWallet* pwallet,
bool fProofOfStake,
std::vector<CStakeableOutput>* availableCoins,
std::vector<CStakeableShieldNote>* availableShieldNotes,
bool fNoMempoolTx,
bool fTestValidity,
CBlockIndex* prevBlock,
bool stopPoSOnNewBlock,
bool fIncludeQfc)
{
resetBlock();

Expand All @@ -187,8 +188,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
}

// Depending on the tip height, try to find a coinstake who solves the block or create a coinbase tx.
if (!(fProofOfStake ? SolveProofOfStake(pblock, pindexPrev, pwallet, availableCoins, stopPoSOnNewBlock)
: CreateCoinbaseTx(pblock, scriptPubKeyIn, pindexPrev))) {
if (!(fProofOfStake ? SolveProofOfStake(pblock, pindexPrev, pwallet, availableCoins, availableShieldNotes, stopPoSOnNewBlock) : CreateCoinbaseTx(pblock, scriptPubKeyIn, pindexPrev))) {
return nullptr;
}

Expand Down
19 changes: 11 additions & 8 deletions src/blockassembler.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#define PIVX_BLOCKASSEMBLER_H

#include "primitives/block.h"
#include "sapling/saplingscriptpubkeyman.h"
#include "stakeinput.h"
#include "txmempool.h"

#include <stdint.h>
Expand Down Expand Up @@ -163,14 +165,15 @@ class BlockAssembler
BlockAssembler(const CChainParams& chainparams, const bool defaultPrintPriority);
/** Construct a new block template with coinbase to scriptPubKeyIn */
std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn,
CWallet* pwallet = nullptr,
bool fProofOfStake = false,
std::vector<CStakeableOutput>* availableCoins = nullptr,
bool fNoMempoolTx = false,
bool fTestValidity = true,
CBlockIndex* prevBlock = nullptr,
bool stopPoSOnNewBlock = true,
bool fIncludeQfc = true);
CWallet* pwallet = nullptr,
bool fProofOfStake = false,
std::vector<CStakeableOutput>* availableCoins = nullptr,
std::vector<CStakeableShieldNote>* availableShieldNotes = nullptr,
bool fNoMempoolTx = false,
bool fTestValidity = true,
CBlockIndex* prevBlock = nullptr,
bool stopPoSOnNewBlock = true,
bool fIncludeQfc = true);

private:
// utility functions
Expand Down
1 change: 1 addition & 0 deletions src/kernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ CStakeKernel::CStakeKernel(const CBlockIndex* const pindexPrev, CStakeInput* sta
nTimeBlockFrom = pindexFrom->nTime;
} else {
if (!Params().GetConsensus().NetworkUpgradeActive(pindexPrev->nHeight + 1, Consensus::UPGRADE_SHIELD_STAKING)) {
std::cout << "Data: " << stakeInput->GetValue() << std::endl;
LogPrintf("%s : ShieldStaking is not yet active!", __func__);
} else {
stakeModifier << pindexPrev->GetStakeModifierV2();
Expand Down
12 changes: 7 additions & 5 deletions src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ bool ProcessBlockFound(const std::shared_ptr<const CBlock>& pblock, CWallet& wal
bool fGenerateBitcoins = false;
bool fStakeableCoins = false;

void CheckForCoins(CWallet* pwallet, std::vector<CStakeableOutput>* availableCoins)
void CheckForCoins(CWallet* pwallet, std::vector<CStakeableOutput>* availableCoins, std::vector<CStakeableShieldNote>* availableShieldNotes)
{
if (!pwallet || !pwallet->pStakerStatus)
return;
Expand All @@ -108,6 +108,7 @@ void CheckForCoins(CWallet* pwallet, std::vector<CStakeableOutput>* availableCoi
return;
}
fStakeableCoins = pwallet->StakeableCoins(availableCoins);
pwallet->StakeableShieldNotes(availableShieldNotes);
}

void BitcoinMiner(CWallet* pwallet, bool fProofOfStake)
Expand All @@ -123,6 +124,7 @@ void BitcoinMiner(CWallet* pwallet, bool fProofOfStake)

// Available UTXO set
std::vector<CStakeableOutput> availableCoins;
std::vector<CStakeableShieldNote> availableShieldNotes;
unsigned int nExtraNonce = 0;

while (fGenerateBitcoins || fProofOfStake) {
Expand All @@ -139,13 +141,13 @@ void BitcoinMiner(CWallet* pwallet, bool fProofOfStake)
}

// update fStakeableCoins
CheckForCoins(pwallet, &availableCoins);
CheckForCoins(pwallet, &availableCoins, &availableShieldNotes);

while ((g_connman && g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0 && Params().MiningRequiresPeers())
|| pwallet->IsLocked() || !fStakeableCoins || masternodeSync.NotCompleted()) {
MilliSleep(5000);
// Do another check here to ensure fStakeableCoins is updated
if (!fStakeableCoins) CheckForCoins(pwallet, &availableCoins);
if (!fStakeableCoins) CheckForCoins(pwallet, &availableCoins, &availableShieldNotes);
}

//search our map of hashed blocks, see if bestblock has been hashed yet
Expand All @@ -168,8 +170,8 @@ void BitcoinMiner(CWallet* pwallet, bool fProofOfStake)
unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();

std::unique_ptr<CBlockTemplate> pblocktemplate((fProofOfStake ?
BlockAssembler(Params(), DEFAULT_PRINTPRIORITY).CreateNewBlock(CScript(), pwallet, true, &availableCoins) :
CreateNewBlockWithKey(pReservekey, pwallet)));
BlockAssembler(Params(), DEFAULT_PRINTPRIORITY).CreateNewBlock(CScript(), pwallet, true, &availableCoins, &availableShieldNotes) :
CreateNewBlockWithKey(pReservekey, pwallet)));
if (!pblocktemplate) continue;
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>(pblocktemplate->block);

Expand Down
6 changes: 4 additions & 2 deletions src/rpc/mining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,15 @@ UniValue generateBlocks(const Consensus::Params& consensus,

// Get available coins
std::vector<CStakeableOutput> availableCoins;
std::vector<CStakeableShieldNote> availableShieldNotes;
pwallet->StakeableShieldNotes(&availableShieldNotes);
if (fPoS && !pwallet->StakeableCoins(&availableCoins)) {
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "No available coins to stake");
}

std::unique_ptr<CBlockTemplate> pblocktemplate(fPoS ?
BlockAssembler(Params(), DEFAULT_PRINTPRIORITY).CreateNewBlock(CScript(), pwallet, true, &availableCoins) :
CreateNewBlockWithScript(*coinbaseScript, pwallet));
BlockAssembler(Params(), DEFAULT_PRINTPRIORITY).CreateNewBlock(CScript(), pwallet, true, &availableCoins, &availableShieldNotes) :
CreateNewBlockWithScript(*coinbaseScript, pwallet));
if (!pblocktemplate.get()) break;
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>(pblocktemplate->block);

Expand Down
5 changes: 3 additions & 2 deletions src/sapling/saplingscriptpubkeyman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ void SaplingScriptPubKeyMan::GetFilteredNotes(
}
}
}
void SaplingScriptPubKeyMan::GetStakableNotes(std::vector<CShieldStake>& shieldInputs, int minDepth)
void SaplingScriptPubKeyMan::GetStakeableNotes(std::vector<CStakeableShieldNote>* shieldInputs, int minDepth)
{
LOCK(wallet->cs_wallet);
for (auto& p : wallet->mapWallet) {
Expand Down Expand Up @@ -580,7 +580,8 @@ void SaplingScriptPubKeyMan::GetStakableNotes(std::vector<CShieldStake>& shieldI
if (nd.nullifier && IsSaplingSpent(*nd.nullifier)) {
continue;
}
shieldInputs.emplace_back(CShieldStake(note.value(), *nd.nullifier));
SaplingNoteEntry noteEntry = SaplingNoteEntry(op, pa, note, notePt.memo(), depth);
shieldInputs->emplace_back(CStakeableShieldNote(noteEntry, *nd.nullifier));
}
}
}
Expand Down
8 changes: 7 additions & 1 deletion src/sapling/saplingscriptpubkeyman.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ struct SaplingNoteEntry
int confirmations;
};

struct CStakeableShieldNote {
explicit CStakeableShieldNote(const SaplingNoteEntry& _note, const uint256 _nullifier) : note(_note), nullifier(_nullifier) {}
SaplingNoteEntry note;
uint256 nullifier;
};

class SaplingNoteData
{
public:
Expand Down Expand Up @@ -295,7 +301,7 @@ class SaplingScriptPubKeyMan {
bool ignoreLocked=true) const;

/* Return a list of notes that are stakable */
void GetStakableNotes(std::vector<CShieldStake>& shieldInputs, int minDepth);
void GetStakeableNotes(std::vector<CStakeableShieldNote>* shieldInputs, int minDepth);

/* Return list of available notes grouped by sapling address. */
std::map<libzcash::SaplingPaymentAddress, std::vector<SaplingNoteEntry>> ListNotes() const;
Expand Down
20 changes: 11 additions & 9 deletions src/test/test_pivx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,15 +201,17 @@ CBlock TestChainSetup::CreateBlock(const std::vector<CMutableTransaction>& txns,
CBlockIndex* customPrevBlock)
{
std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(
Params(), DEFAULT_PRINTPRIORITY).CreateNewBlock(scriptPubKey,
nullptr, // wallet
false, // fProofOfStake
nullptr, // availableCoins
fNoMempoolTx,
fTestBlockValidity,
customPrevBlock,
true,
fIncludeQfc);
Params(), DEFAULT_PRINTPRIORITY)
.CreateNewBlock(scriptPubKey,
nullptr, // wallet
false, // fProofOfStake
nullptr, // availableCoins
nullptr, // availableShieldCoins
fNoMempoolTx,
fTestBlockValidity,
customPrevBlock,
true,
fIncludeQfc);
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>(pblocktemplate->block);

// Add passed-in txns:
Expand Down
35 changes: 21 additions & 14 deletions src/wallet/test/pos_validations_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,17 @@ BOOST_FIXTURE_TEST_CASE(coinstake_tests, TestPoSChainSetup)

// Let's create the block
std::vector<CStakeableOutput> availableCoins;
std::vector<CStakeableShieldNote> availableShieldNotes;
BOOST_CHECK(pwalletMain->StakeableCoins(&availableCoins));
pwalletMain->StakeableShieldNotes(&availableShieldNotes);
std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(
Params(), false).CreateNewBlock(CScript(),
pwalletMain.get(),
true,
&availableCoins,
true);
Params(), false)
.CreateNewBlock(CScript(),
pwalletMain.get(),
true,
&availableCoins,
&availableShieldNotes,
true);
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>(pblocktemplate->block);
BOOST_CHECK(pblock->IsProofOfStake());

Expand Down Expand Up @@ -143,8 +147,9 @@ std::shared_ptr<CBlock> CreateBlockInternal(CWallet* pwalletMain, const std::vec
std::initializer_list<std::shared_ptr<CBlock>> forkchain = {})
{
std::vector<CStakeableOutput> availableCoins;
std::vector<CStakeableShieldNote> availableShieldNotes;
BOOST_CHECK(pwalletMain->StakeableCoins(&availableCoins));

pwalletMain->StakeableShieldNotes(&availableShieldNotes);
// Remove any utxo which is not deeper than 120 blocks (for the same reasoning
// used when selecting tx inputs in CreateAndCommitTx)
// Also, as the wallet is not prepared to follow several chains at the same time,
Expand All @@ -160,14 +165,16 @@ std::shared_ptr<CBlock> CreateBlockInternal(CWallet* pwalletMain, const std::vec
}

std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(
Params(), false).CreateNewBlock(CScript(),
pwalletMain,
true,
&availableCoins,
true,
false,
customPrevBlock,
false);
Params(), false)
.CreateNewBlock(CScript(),
pwalletMain,
true,
&availableCoins,
&availableShieldNotes,
true,
false,
customPrevBlock,
false);
BOOST_ASSERT(pblocktemplate);
auto pblock = std::make_shared<CBlock>(pblocktemplate->block);
if (!txns.empty()) {
Expand Down
51 changes: 43 additions & 8 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2695,6 +2695,12 @@ bool CWallet::StakeableCoins(std::vector<CStakeableOutput>* pCoins)
return (pCoins && !pCoins->empty());
}

void CWallet::StakeableShieldNotes(std::vector<CStakeableShieldNote>* shieldCoins)
{
shieldCoins->clear();
m_sspk_man->GetStakeableNotes(shieldCoins, Params().GetConsensus().nStakeMinDepth);
}

bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, uint64_t nMaxAncestors, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*, unsigned int> >& setCoinsRet, CAmount& nValueRet) const
{
setCoinsRet.clear();
Expand Down Expand Up @@ -3309,12 +3315,13 @@ bool CWallet::CreateCoinstakeOuts(const CPivStake& stakeInput, std::vector<CTxOu
}

bool CWallet::CreateCoinStake(
const CBlockIndex* pindexPrev,
unsigned int nBits,
CMutableTransaction& txNew,
int64_t& nTxNewTime,
std::vector<CStakeableOutput>* availableCoins,
bool stopOnNewBlock) const
const CBlockIndex* pindexPrev,
unsigned int nBits,
CMutableTransaction& txNew,
int64_t& nTxNewTime,
std::vector<CStakeableOutput>* availableCoins,
std::vector<CStakeableShieldNote>* availableShieldNotes,
bool stopOnNewBlock) const
{
// shuffle coins
if (availableCoins && Params().IsRegTestNet()) {
Expand All @@ -3336,6 +3343,7 @@ bool CWallet::CreateCoinStake(
CScript scriptPubKeyKernel;
bool fKernelFound = false;
int nAttempts = 0;
int nShieldAttempts = 0;
for (auto it = availableCoins->begin(); it != availableCoins->end();) {
COutPoint outPoint = COutPoint(it->tx->GetHash(), it->i);
CPivStake stakeInput(it->tx->tx->vout[it->i],
Expand Down Expand Up @@ -3409,9 +3417,36 @@ bool CWallet::CreateCoinStake(
if (nBytes >= DEFAULT_BLOCK_MAX_SIZE / 5)
return error("%s : exceeded coinstake size limit", __func__);

break;
LogPrint(BCLog::STAKING, "%s: shield attempted staking %d times\n", __func__, nShieldAttempts);
return fKernelFound;
}
LogPrint(BCLog::STAKING, "%s: transparent attempted staking %d times\n", __func__, nAttempts);
// Resetting tx values
txNew.vin.clear();
txNew.vout.clear();
for (auto it = availableShieldNotes->begin(); it != availableShieldNotes->end();) {
CShieldStake noteStake = CShieldStake(it->note.note.value(), it->nullifier);
// New block came in, move on
if (stopOnNewBlock && GetLastBlockHeightLockWallet() != pindexPrev->nHeight) return false;

// Make sure the wallet is unlocked and shutdown hasn't been requested
if (IsLocked() || ShutdownRequested()) return false;

// TODO: check that the note IS NOT spent
nShieldAttempts++;
nCredit = 0;
bool fKernelFound = false;
fKernelFound = Stake(pindexPrev, &noteStake, nBits, nTxNewTime);
// update staker status (time, attempts)
pStakerStatus->SetLastTime(nTxNewTime);
pStakerStatus->SetLastTries(nAttempts + nShieldAttempts);

if (!fKernelFound) {
it++;
continue;
}
}
LogPrint(BCLog::STAKING, "%s: attempted staking %d times\n", __func__, nAttempts);
LogPrint(BCLog::STAKING, "%s: shield attempted staking %d times\n", __func__, nShieldAttempts);

return fKernelFound;
}
Expand Down
Loading

0 comments on commit 7277289

Please sign in to comment.