Skip to content

Commit

Permalink
Shield staking Functional test
Browse files Browse the repository at this point in the history
  • Loading branch information
panleone authored and Duddino committed Sep 13, 2023
1 parent c69c3ac commit b09c23e
Show file tree
Hide file tree
Showing 15 changed files with 334 additions and 111 deletions.
4 changes: 3 additions & 1 deletion src/blockassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ bool SolveProofOfStake(CBlock* pblock, CBlockIndex* pindexPrev, CMutableTransact

if (pblock->IsProofOfShieldStake()) {
auto& shieldStake = *static_cast<CStakeableShieldNote*>(pStake);
pwallet->ComputeShieldStakeProof(*pblock, shieldStake, shieldStake.note.value());
if (!pwallet->GetSaplingScriptPubKeyMan()->ComputeShieldStakeProof(*pblock, shieldStake, shieldStake.suggestedValue)) {
return false;
}
}
return true;
}
Expand Down
124 changes: 64 additions & 60 deletions src/consensus/upgrades.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,66 +13,70 @@
* We are using it in the -nuparams startup arg and input it with spaces is just ugly.
*/
const struct NUInfo NetworkUpgradeInfo[Consensus::MAX_NETWORK_UPGRADES] = {
{
/*.strName =*/ "Base",
/*.strInfo =*/ "PIVX network",
},
{
/*.strName =*/ "PoS",
/*.strInfo =*/ "Proof of Stake Consensus activation",
},
{
/*.strName =*/ "PoS_v2",
/*.strInfo =*/ "New selection for stake modifier",
},
{
/*.strName =*/ "Zerocoin",
/*.strInfo =*/ "ZeroCoin protocol activation - start block v4",
},
{
/*.strName =*/ "Zerocoin_v2",
/*.strInfo =*/ "New zerocoin serials and zPOS start",
},
{
/*.strName =*/ "BIP65",
/*.strInfo =*/ "CLTV (BIP65) activation - start block v5",
},
{
/*.strName =*/ "Zerocoin_Public",
/*.strInfo =*/ "Activation of zerocoin public spends (spend v3)",
},
{
/*.strName =*/ "PIVX_v3.4",
/*.strInfo =*/ "New 256-bit stake modifier - start block v6",
},
{
/*.strName =*/ "PIVX_v4.0",
/*.strInfo =*/ "New message sigs - start block v7 - time protocol - zc spend v4",
},
{
/*.strName =*/ "v5_shield",
/*.strInfo =*/ "Sapling Shield - start block v8 - start transaction v3",
},
{
/*.strName =*/ "PIVX_v5.2",
/*.strInfo =*/ "New cold-staking rules",
},
{
/*.strName =*/ "PIVX_v5.3",
/*.strInfo =*/ "New staking rules",
},
{
/*.strName =*/ "PIVX_v5.5",
/*.strInfo =*/ "New rewards structure",
},
{
/*.strName =*/ "v6_evo",
/*.strInfo =*/ "Deterministic Masternodes",
},
{
/*.strName =*/ "Test_dummy",
/*.strInfo =*/ "Test dummy info",
},
{
/*.strName =*/"Base",
/*.strInfo =*/"PIVX network",
},
{
/*.strName =*/"PoS",
/*.strInfo =*/"Proof of Stake Consensus activation",
},
{
/*.strName =*/"PoS_v2",
/*.strInfo =*/"New selection for stake modifier",
},
{
/*.strName =*/"Zerocoin",
/*.strInfo =*/"ZeroCoin protocol activation - start block v4",
},
{
/*.strName =*/"Zerocoin_v2",
/*.strInfo =*/"New zerocoin serials and zPOS start",
},
{
/*.strName =*/"BIP65",
/*.strInfo =*/"CLTV (BIP65) activation - start block v5",
},
{
/*.strName =*/"Zerocoin_Public",
/*.strInfo =*/"Activation of zerocoin public spends (spend v3)",
},
{
/*.strName =*/"PIVX_v3.4",
/*.strInfo =*/"New 256-bit stake modifier - start block v6",
},
{
/*.strName =*/"PIVX_v4.0",
/*.strInfo =*/"New message sigs - start block v7 - time protocol - zc spend v4",
},
{
/*.strName =*/"v5_shield",
/*.strInfo =*/"Sapling Shield - start block v8 - start transaction v3",
},
{
/*.strName =*/"PIVX_v5.2",
/*.strInfo =*/"New cold-staking rules",
},
{
/*.strName =*/"PIVX_v5.3",
/*.strInfo =*/"New staking rules",
},
{
/*.strName =*/"PIVX_v5.5",
/*.strInfo =*/"New rewards structure",
},
{
/*.strName =*/"v6_evo",
/*.strInfo =*/"Deterministic Masternodes",
},
{
/*.strName =*/"shield_staking",
/*.strInfo =*/"Shield Staking",
},
{
/*.strName =*/"Test_dummy",
/*.strInfo =*/"Test dummy info",
},
};

UpgradeState NetworkUpgradeState(
Expand Down
22 changes: 18 additions & 4 deletions src/kernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include "kernel.h"

#include "arith_uint256.h"
#include "chainparams.h"
#include "consensus/params.h"
#include "consensus/validation.h"
Expand Down Expand Up @@ -70,7 +71,7 @@ uint256 CStakeKernel::GetHash() const
}

// Check that the kernel hash meets the target required
bool CStakeKernel::CheckKernelHash(bool fSkipLog) const
bool CStakeKernel::CheckKernelHash(bool fSkipLog)
{
// Get weighted target
arith_uint256 bnTarget;
Expand All @@ -80,7 +81,8 @@ bool CStakeKernel::CheckKernelHash(bool fSkipLog) const
// Check PoS kernel hash
const arith_uint256& hashProofOfStake = UintToArith256(GetHash());
const bool res = hashProofOfStake < bnTarget;

suggestedValue = ComputeSuggestedValue(stakeValue, bnTarget, hashProofOfStake);
LogPrintf("%d\n", suggestedValue);
if (!fSkipLog || res) {
LogPrint(BCLog::STAKING, "%s : Proof Of Stake:"
"\nstakeModifier=%s"
Expand All @@ -97,6 +99,14 @@ bool CStakeKernel::CheckKernelHash(bool fSkipLog) const
return res;
}

CAmount CStakeKernel::ComputeSuggestedValue(CAmount stakevalue, const arith_uint256& bnTarget, const arith_uint256& hashProofOfStake) const
{
arith_uint256 diff;
diff.SetCompact(nBits);
auto total = static_cast<CAmount>((((hashProofOfStake) / diff).Get64() + 1) * 100);
if (total > stakevalue) return stakevalue;
return total;
}

/*
* PoS Validation
Expand Down Expand Up @@ -135,7 +145,7 @@ static bool LoadStakeInput(const CBlock& block, std::unique_ptr<CStakeInput>& st
* @param[in] nTimeTx new blocktime
* @return bool true if stake kernel hash meets target protocol
*/
bool Stake(const CBlockIndex* pindexPrev, CStakeInput* stakeInput, unsigned int nBits, int64_t& nTimeTx)
bool Stake(const CBlockIndex* pindexPrev, CStakeInput* stakeInput, unsigned int nBits, int64_t& nTimeTx, CAmount* suggestedValue)
{
if (!stakeInput) return false;

Expand All @@ -146,7 +156,11 @@ bool Stake(const CBlockIndex* pindexPrev, CStakeInput* stakeInput, unsigned int

// Verify Proof Of Stake
CStakeKernel stakeKernel(pindexPrev, stakeInput, nBits, nTimeTx);
return stakeKernel.CheckKernelHash(true);
bool check = stakeKernel.CheckKernelHash(true);
if (suggestedValue)
*suggestedValue = stakeKernel.GetSuggestedValue();

return check;
}

// This checks if the provided note value is valid
Expand Down
11 changes: 9 additions & 2 deletions src/kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#ifndef PIVX_KERNEL_H
#define PIVX_KERNEL_H

#include "arith_uint256.h"
#include "stakeinput.h"

class CStakeKernel {
Expand All @@ -26,7 +27,11 @@ class CStakeKernel {
uint256 GetHash() const;

// Check that the kernel hash meets the target required
bool CheckKernelHash(bool fSkipLog = false) const;
bool CheckKernelHash(bool fSkipLog = false);
CAmount GetSuggestedValue() const
{
return suggestedValue;
}

private:
// kernel message hashed
Expand All @@ -37,6 +42,8 @@ class CStakeKernel {
// hash target
unsigned int nBits{0}; // difficulty for the target
CAmount stakeValue{0}; // target multiplier
CAmount suggestedValue{0};
CAmount ComputeSuggestedValue(CAmount stakevalue, const arith_uint256& bnTarget, const arith_uint256& hashProofOfStake) const;
};

/* PoS Validation */
Expand All @@ -50,7 +57,7 @@ class CStakeKernel {
* @param[in] nTimeTx new blocktime
* @return bool true if stake kernel hash meets target protocol
*/
bool Stake(const CBlockIndex* pindexPrev, CStakeInput* stakeInput, unsigned int nBits, int64_t& nTimeTx);
bool Stake(const CBlockIndex* pindexPrev, CStakeInput* stakeInput, unsigned int nBits, int64_t& nTimeTx, CAmount* suggestedValue = nullptr);

/*
* CheckProofOfStake Check if block has valid proof of stake
Expand Down
36 changes: 28 additions & 8 deletions src/primitives/block.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,22 +81,42 @@ class ShieldStakeProof
{
public:
CAmount amount;
SpendDescription input;
OutputDescription output;
std::vector<unsigned char> bindingSig;
uint256 inputCv;
uint256 rk;
SpendDescription::spend_auth_sig_t spendSig;
libzcash::GrothProof inputProof = {{0}};

uint256 outputCv;
uint256 epk;
uint256 cmu;
libzcash::GrothProof outputProof = {{0}};
libzcash::GrothProof sig = {{0}};

void SetNull()
{
amount = 0;
output = OutputDescription();
bindingSig.clear();
inputCv.SetNull();
spendSig = {{0}};
rk.SetNull();
inputProof = {{0}};
outputCv.SetNull();
epk.SetNull();
cmu.SetNull();
outputProof = {{0}};
}

SERIALIZE_METHODS(ShieldStakeProof, obj)
{
READWRITE(obj.amount);
READWRITE(obj.output);
READWRITE(obj.bindingSig);
READWRITE(obj.inputCv);
READWRITE(obj.rk);
READWRITE(obj.spendSig);
READWRITE(obj.inputProof);
READWRITE(obj.epk);
READWRITE(obj.cmu);
READWRITE(obj.outputCv);
READWRITE(obj.outputProof);
READWRITE(obj.sig);
}
};

Expand Down Expand Up @@ -134,7 +154,7 @@ class CBlock : public CBlockHeader
READWRITE(obj.vchBlockSig);

// Shield Staking Proof
if (obj.nVersion >= 12 && obj.IsProofOfStake()) {
if (obj.nVersion >= 12 && obj.IsProofOfShieldStake()) {
READWRITE(obj.shieldStakeProof);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/primitives/transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ bool CTransaction::IsCoinStake() const
{
if (vin.empty())
return false;
if (!sapData->vShieldedSpend.empty())
if (sapData && !sapData->vShieldedSpend.empty())
return false;
bool fAllowNull = vin[0].IsZerocoinSpend();
if (vin[0].prevout.IsNull() && !fAllowNull)
Expand Down
4 changes: 4 additions & 0 deletions src/rpc/blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn
result.pushKV("bits", strprintf("%08x", block.nBits));
result.pushKV("difficulty", GetDifficulty(blockindex));
result.pushKV("chainwork", blockindex->nChainWork.GetHex());
if (block.IsProofOfShieldStake()) {
auto& p = block.shieldStakeProof;
result.pushKV("shieldproofamount", p.amount);
}

if (blockindex->pprev)
result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex());
Expand Down
57 changes: 34 additions & 23 deletions src/sapling/sapling_validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,36 +232,47 @@ bool CheckShieldStake(const CBlock& block, CValidationState& state, const CChain
if (!block.IsProofOfShieldStake()) {
return false;
}
return true;
// TODO: check rest
// In addition to the regular checks for a tx, we also have to ensure that the provided
// shieldStakeAmount is valid. To do this without creating a new circuit, the staker inserts
// a dummy note in the proof, so that Input - DummyNote = shieldStakeAmount.
// To prevent others from potentially spending that note, we change the output proof sighash
auto* saplingCtx = librustzcash_sapling_verification_ctx_init();
LogPrintf("%d", block.shieldStakeProof.amount);

const auto& saplingData = block.vtx[1].get()->sapData.get();
const auto& spend = saplingData.vShieldedSpend[0];
auto ctx = librustzcash_sapling_verification_ctx_init();
const auto& inputNote = saplingData.vShieldedSpend[0];
const auto& p = block.shieldStakeProof;
const int DOS_LEVEL_BLOCK = 100;

uint256 dataToBeSigned;
// TODO: get the sighash
if (!librustzcash_sapling_check_spend(saplingCtx, spend.cv.begin(), spend.anchor.begin(), spend.nullifier.begin(), spend.rk.begin(), spend.zkproof.begin(), spend.spendAuthSig.begin(), dataToBeSigned.begin())) {
librustzcash_sapling_verification_ctx_free(saplingCtx);
return false;
}
const auto& output = block.shieldStakeProof.output;
if (!librustzcash_sapling_check_output(saplingCtx, output.cv.begin(), output.cmu.begin(), output.ephemeralKey.begin(), output.zkproof.begin())) {
librustzcash_sapling_verification_ctx_free(saplingCtx);
return false;
try {
// TODO: write signature for shield
// dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL, 0, SIGVERSION_SAPLING);
} catch (const std::logic_error& ex) {
// A logic error should never occur because we pass NOT_AN_INPUT and
// SIGHASH_ALL to SignatureHash().
return state.DoS(100, error("%s: error computing signature hash", __func__),
REJECT_INVALID, "error-computing-signature-hash");
}

// dataToBeSigned = ...;
if (!librustzcash_sapling_check_spend(ctx, p.inputCv.begin(), inputNote.anchor.begin(), inputNote.nullifier.begin(), p.rk.begin(), p.inputProof.begin(), p.spendSig.begin(), dataToBeSigned.begin())) {
librustzcash_sapling_verification_ctx_free(ctx);
return state.DoS(
DOS_LEVEL_BLOCK,
error("%s: Sapling spend description invalid", __func__),
REJECT_INVALID, "bad-txns-sapling-spend-description-invalid");
}

if (!librustzcash_sapling_final_check(saplingCtx, block.shieldStakeProof.amount, block.shieldStakeProof.bindingSig.data(), dataToBeSigned.begin())) {
librustzcash_sapling_verification_ctx_free(saplingCtx);
return false;
if (!librustzcash_sapling_check_output(ctx, p.outputCv.begin(), p.cmu.begin(), p.epk.begin(), p.outputProof.begin())) {
librustzcash_sapling_verification_ctx_free(ctx);
return state.DoS(100, error("%s: Sapling output description invalid", __func__),
REJECT_INVALID, "bad-txns-sapling-output-description-invalid");
}

librustzcash_sapling_verification_ctx_free(saplingCtx);
LogPrintf("Phonenuix");
if (!librustzcash_sapling_final_check(ctx, block.shieldStakeProof.amount, block.shieldStakeProof.sig.data(), dataToBeSigned.begin())) {
librustzcash_sapling_verification_ctx_free(ctx);
return state.DoS(
100,
error("%s: Sapling binding signature invalid", __func__),
REJECT_INVALID, "bad-txns-sapling-binding-signature-invalid");
}
librustzcash_sapling_verification_ctx_free(ctx);
return true;
}

Expand Down
Loading

0 comments on commit b09c23e

Please sign in to comment.