Skip to content

Commit bf96f52

Browse files
committed
Shield staking Functional test
1 parent 6877274 commit bf96f52

File tree

15 files changed

+334
-111
lines changed

15 files changed

+334
-111
lines changed

src/blockassembler.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,9 @@ bool SolveProofOfStake(CBlock* pblock, CBlockIndex* pindexPrev, CMutableTransact
108108

109109
if (pblock->IsProofOfShieldStake()) {
110110
auto& shieldStake = *static_cast<CStakeableShieldNote*>(pStake);
111-
pwallet->ComputeShieldStakeProof(*pblock, shieldStake, shieldStake.note.value());
111+
if (!pwallet->GetSaplingScriptPubKeyMan()->ComputeShieldStakeProof(*pblock, shieldStake, shieldStake.suggestedValue)) {
112+
return false;
113+
}
112114
}
113115
return true;
114116
}

src/consensus/upgrades.cpp

Lines changed: 64 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -13,66 +13,70 @@
1313
* We are using it in the -nuparams startup arg and input it with spaces is just ugly.
1414
*/
1515
const struct NUInfo NetworkUpgradeInfo[Consensus::MAX_NETWORK_UPGRADES] = {
16-
{
17-
/*.strName =*/ "Base",
18-
/*.strInfo =*/ "PIVX network",
19-
},
20-
{
21-
/*.strName =*/ "PoS",
22-
/*.strInfo =*/ "Proof of Stake Consensus activation",
23-
},
24-
{
25-
/*.strName =*/ "PoS_v2",
26-
/*.strInfo =*/ "New selection for stake modifier",
27-
},
28-
{
29-
/*.strName =*/ "Zerocoin",
30-
/*.strInfo =*/ "ZeroCoin protocol activation - start block v4",
31-
},
32-
{
33-
/*.strName =*/ "Zerocoin_v2",
34-
/*.strInfo =*/ "New zerocoin serials and zPOS start",
35-
},
36-
{
37-
/*.strName =*/ "BIP65",
38-
/*.strInfo =*/ "CLTV (BIP65) activation - start block v5",
39-
},
40-
{
41-
/*.strName =*/ "Zerocoin_Public",
42-
/*.strInfo =*/ "Activation of zerocoin public spends (spend v3)",
43-
},
44-
{
45-
/*.strName =*/ "PIVX_v3.4",
46-
/*.strInfo =*/ "New 256-bit stake modifier - start block v6",
47-
},
48-
{
49-
/*.strName =*/ "PIVX_v4.0",
50-
/*.strInfo =*/ "New message sigs - start block v7 - time protocol - zc spend v4",
51-
},
52-
{
53-
/*.strName =*/ "v5_shield",
54-
/*.strInfo =*/ "Sapling Shield - start block v8 - start transaction v3",
55-
},
56-
{
57-
/*.strName =*/ "PIVX_v5.2",
58-
/*.strInfo =*/ "New cold-staking rules",
59-
},
60-
{
61-
/*.strName =*/ "PIVX_v5.3",
62-
/*.strInfo =*/ "New staking rules",
63-
},
64-
{
65-
/*.strName =*/ "PIVX_v5.5",
66-
/*.strInfo =*/ "New rewards structure",
67-
},
68-
{
69-
/*.strName =*/ "v6_evo",
70-
/*.strInfo =*/ "Deterministic Masternodes",
71-
},
72-
{
73-
/*.strName =*/ "Test_dummy",
74-
/*.strInfo =*/ "Test dummy info",
75-
},
16+
{
17+
/*.strName =*/"Base",
18+
/*.strInfo =*/"PIVX network",
19+
},
20+
{
21+
/*.strName =*/"PoS",
22+
/*.strInfo =*/"Proof of Stake Consensus activation",
23+
},
24+
{
25+
/*.strName =*/"PoS_v2",
26+
/*.strInfo =*/"New selection for stake modifier",
27+
},
28+
{
29+
/*.strName =*/"Zerocoin",
30+
/*.strInfo =*/"ZeroCoin protocol activation - start block v4",
31+
},
32+
{
33+
/*.strName =*/"Zerocoin_v2",
34+
/*.strInfo =*/"New zerocoin serials and zPOS start",
35+
},
36+
{
37+
/*.strName =*/"BIP65",
38+
/*.strInfo =*/"CLTV (BIP65) activation - start block v5",
39+
},
40+
{
41+
/*.strName =*/"Zerocoin_Public",
42+
/*.strInfo =*/"Activation of zerocoin public spends (spend v3)",
43+
},
44+
{
45+
/*.strName =*/"PIVX_v3.4",
46+
/*.strInfo =*/"New 256-bit stake modifier - start block v6",
47+
},
48+
{
49+
/*.strName =*/"PIVX_v4.0",
50+
/*.strInfo =*/"New message sigs - start block v7 - time protocol - zc spend v4",
51+
},
52+
{
53+
/*.strName =*/"v5_shield",
54+
/*.strInfo =*/"Sapling Shield - start block v8 - start transaction v3",
55+
},
56+
{
57+
/*.strName =*/"PIVX_v5.2",
58+
/*.strInfo =*/"New cold-staking rules",
59+
},
60+
{
61+
/*.strName =*/"PIVX_v5.3",
62+
/*.strInfo =*/"New staking rules",
63+
},
64+
{
65+
/*.strName =*/"PIVX_v5.5",
66+
/*.strInfo =*/"New rewards structure",
67+
},
68+
{
69+
/*.strName =*/"v6_evo",
70+
/*.strInfo =*/"Deterministic Masternodes",
71+
},
72+
{
73+
/*.strName =*/"shield_staking",
74+
/*.strInfo =*/"Shield Staking",
75+
},
76+
{
77+
/*.strName =*/"Test_dummy",
78+
/*.strInfo =*/"Test dummy info",
79+
},
7680
};
7781

7882
UpgradeState NetworkUpgradeState(

src/kernel.cpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include "kernel.h"
99

10+
#include "arith_uint256.h"
1011
#include "chainparams.h"
1112
#include "consensus/params.h"
1213
#include "consensus/validation.h"
@@ -70,7 +71,7 @@ uint256 CStakeKernel::GetHash() const
7071
}
7172

7273
// Check that the kernel hash meets the target required
73-
bool CStakeKernel::CheckKernelHash(bool fSkipLog) const
74+
bool CStakeKernel::CheckKernelHash(bool fSkipLog)
7475
{
7576
// Get weighted target
7677
arith_uint256 bnTarget;
@@ -80,7 +81,8 @@ bool CStakeKernel::CheckKernelHash(bool fSkipLog) const
8081
// Check PoS kernel hash
8182
const arith_uint256& hashProofOfStake = UintToArith256(GetHash());
8283
const bool res = hashProofOfStake < bnTarget;
83-
84+
suggestedValue = ComputeSuggestedValue(stakeValue, bnTarget, hashProofOfStake);
85+
LogPrintf("%d\n", suggestedValue);
8486
if (!fSkipLog || res) {
8587
LogPrint(BCLog::STAKING, "%s : Proof Of Stake:"
8688
"\nstakeModifier=%s"
@@ -97,6 +99,14 @@ bool CStakeKernel::CheckKernelHash(bool fSkipLog) const
9799
return res;
98100
}
99101

102+
CAmount CStakeKernel::ComputeSuggestedValue(CAmount stakevalue, const arith_uint256& bnTarget, const arith_uint256& hashProofOfStake) const
103+
{
104+
arith_uint256 diff;
105+
diff.SetCompact(nBits);
106+
auto total = static_cast<CAmount>((((hashProofOfStake) / diff).Get64() + 1) * 100);
107+
if (total > stakevalue) return stakevalue;
108+
return total;
109+
}
100110

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

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

147157
// Verify Proof Of Stake
148158
CStakeKernel stakeKernel(pindexPrev, stakeInput, nBits, nTimeTx);
149-
return stakeKernel.CheckKernelHash(true);
159+
bool check = stakeKernel.CheckKernelHash(true);
160+
if (suggestedValue)
161+
*suggestedValue = stakeKernel.GetSuggestedValue();
162+
163+
return check;
150164
}
151165

152166
// This checks if the provided note value is valid

src/kernel.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#ifndef PIVX_KERNEL_H
99
#define PIVX_KERNEL_H
1010

11+
#include "arith_uint256.h"
1112
#include "stakeinput.h"
1213

1314
class CStakeKernel {
@@ -26,7 +27,11 @@ class CStakeKernel {
2627
uint256 GetHash() const;
2728

2829
// Check that the kernel hash meets the target required
29-
bool CheckKernelHash(bool fSkipLog = false) const;
30+
bool CheckKernelHash(bool fSkipLog = false);
31+
CAmount GetSuggestedValue() const
32+
{
33+
return suggestedValue;
34+
}
3035

3136
private:
3237
// kernel message hashed
@@ -37,6 +42,8 @@ class CStakeKernel {
3742
// hash target
3843
unsigned int nBits{0}; // difficulty for the target
3944
CAmount stakeValue{0}; // target multiplier
45+
CAmount suggestedValue{0};
46+
CAmount ComputeSuggestedValue(CAmount stakevalue, const arith_uint256& bnTarget, const arith_uint256& hashProofOfStake) const;
4047
};
4148

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

5562
/*
5663
* CheckProofOfStake Check if block has valid proof of stake

src/primitives/block.h

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,22 +81,42 @@ class ShieldStakeProof
8181
{
8282
public:
8383
CAmount amount;
84-
SpendDescription input;
85-
OutputDescription output;
86-
std::vector<unsigned char> bindingSig;
84+
uint256 inputCv;
85+
uint256 rk;
86+
SpendDescription::spend_auth_sig_t spendSig;
87+
libzcash::GrothProof inputProof = {{0}};
88+
89+
uint256 outputCv;
90+
uint256 epk;
91+
uint256 cmu;
92+
libzcash::GrothProof outputProof = {{0}};
93+
libzcash::GrothProof sig = {{0}};
8794

8895
void SetNull()
8996
{
9097
amount = 0;
91-
output = OutputDescription();
92-
bindingSig.clear();
98+
inputCv.SetNull();
99+
spendSig = {{0}};
100+
rk.SetNull();
101+
inputProof = {{0}};
102+
outputCv.SetNull();
103+
epk.SetNull();
104+
cmu.SetNull();
105+
outputProof = {{0}};
93106
}
94107

95108
SERIALIZE_METHODS(ShieldStakeProof, obj)
96109
{
97110
READWRITE(obj.amount);
98-
READWRITE(obj.output);
99-
READWRITE(obj.bindingSig);
111+
READWRITE(obj.inputCv);
112+
READWRITE(obj.rk);
113+
READWRITE(obj.spendSig);
114+
READWRITE(obj.inputProof);
115+
READWRITE(obj.epk);
116+
READWRITE(obj.cmu);
117+
READWRITE(obj.outputCv);
118+
READWRITE(obj.outputProof);
119+
READWRITE(obj.sig);
100120
}
101121
};
102122

@@ -134,7 +154,7 @@ class CBlock : public CBlockHeader
134154
READWRITE(obj.vchBlockSig);
135155

136156
// Shield Staking Proof
137-
if (obj.nVersion >= 12 && obj.IsProofOfStake()) {
157+
if (obj.nVersion >= 12 && obj.IsProofOfShieldStake()) {
138158
READWRITE(obj.shieldStakeProof);
139159
}
140160
}

src/primitives/transaction.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ bool CTransaction::IsCoinStake() const
135135
{
136136
if (vin.empty())
137137
return false;
138-
if (!sapData->vShieldedSpend.empty())
138+
if (sapData && !sapData->vShieldedSpend.empty())
139139
return false;
140140
bool fAllowNull = vin[0].IsZerocoinSpend();
141141
if (vin[0].prevout.IsNull() && !fAllowNull)

src/rpc/blockchain.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,10 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn
168168
result.pushKV("bits", strprintf("%08x", block.nBits));
169169
result.pushKV("difficulty", GetDifficulty(blockindex));
170170
result.pushKV("chainwork", blockindex->nChainWork.GetHex());
171+
if (block.IsProofOfShieldStake()) {
172+
auto& p = block.shieldStakeProof;
173+
result.pushKV("shieldproofamount", p.amount);
174+
}
171175

172176
if (blockindex->pprev)
173177
result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex());

src/sapling/sapling_validation.cpp

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -232,36 +232,47 @@ bool CheckShieldStake(const CBlock& block, CValidationState& state, const CChain
232232
if (!block.IsProofOfShieldStake()) {
233233
return false;
234234
}
235-
return true;
236-
// TODO: check rest
237-
// In addition to the regular checks for a tx, we also have to ensure that the provided
238-
// shieldStakeAmount is valid. To do this without creating a new circuit, the staker inserts
239-
// a dummy note in the proof, so that Input - DummyNote = shieldStakeAmount.
240-
// To prevent others from potentially spending that note, we change the output proof sighash
241-
auto* saplingCtx = librustzcash_sapling_verification_ctx_init();
235+
LogPrintf("%d", block.shieldStakeProof.amount);
236+
242237
const auto& saplingData = block.vtx[1].get()->sapData.get();
243-
const auto& spend = saplingData.vShieldedSpend[0];
238+
auto ctx = librustzcash_sapling_verification_ctx_init();
239+
const auto& inputNote = saplingData.vShieldedSpend[0];
240+
const auto& p = block.shieldStakeProof;
241+
const int DOS_LEVEL_BLOCK = 100;
242+
244243
uint256 dataToBeSigned;
245-
// TODO: get the sighash
246-
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())) {
247-
librustzcash_sapling_verification_ctx_free(saplingCtx);
248-
return false;
249-
}
250-
const auto& output = block.shieldStakeProof.output;
251-
if (!librustzcash_sapling_check_output(saplingCtx, output.cv.begin(), output.cmu.begin(), output.ephemeralKey.begin(), output.zkproof.begin())) {
252-
librustzcash_sapling_verification_ctx_free(saplingCtx);
253-
return false;
244+
try {
245+
// TODO: write signature for shield
246+
// dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL, 0, SIGVERSION_SAPLING);
247+
} catch (const std::logic_error& ex) {
248+
// A logic error should never occur because we pass NOT_AN_INPUT and
249+
// SIGHASH_ALL to SignatureHash().
250+
return state.DoS(100, error("%s: error computing signature hash", __func__),
251+
REJECT_INVALID, "error-computing-signature-hash");
254252
}
255253

256-
// dataToBeSigned = ...;
254+
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())) {
255+
librustzcash_sapling_verification_ctx_free(ctx);
256+
return state.DoS(
257+
DOS_LEVEL_BLOCK,
258+
error("%s: Sapling spend description invalid", __func__),
259+
REJECT_INVALID, "bad-txns-sapling-spend-description-invalid");
260+
}
257261

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

263-
librustzcash_sapling_verification_ctx_free(saplingCtx);
264-
LogPrintf("Phonenuix");
268+
if (!librustzcash_sapling_final_check(ctx, block.shieldStakeProof.amount, block.shieldStakeProof.sig.data(), dataToBeSigned.begin())) {
269+
librustzcash_sapling_verification_ctx_free(ctx);
270+
return state.DoS(
271+
100,
272+
error("%s: Sapling binding signature invalid", __func__),
273+
REJECT_INVALID, "bad-txns-sapling-binding-signature-invalid");
274+
}
275+
librustzcash_sapling_verification_ctx_free(ctx);
265276
return true;
266277
}
267278

0 commit comments

Comments
 (0)