Bitcoin ABC 0.30.5
P2P Digital Currency
proof.cpp
Go to the documentation of this file.
1// Copyright (c) 2020 The Bitcoin developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include <avalanche/proof.h>
6
8#include <coins.h>
9#include <common/args.h>
10#include <hash.h>
11#include <policy/policy.h>
12#include <script/standard.h>
13#include <streams.h>
14#include <util/strencodings.h>
15#include <util/translation.h>
16
17#include <tinyformat.h>
18
19#include <numeric>
20#include <unordered_set>
21#include <variant>
22
23namespace avalanche {
24
25StakeCommitment::StakeCommitment(int64_t expirationTime,
26 const CPubKey &master) {
27 HashWriter ss{};
28 ss << expirationTime;
29 ss << master;
30 const uint256 &hash = ss.GetHash();
31 memcpy(m_data, hash.data(), sizeof(m_data));
32}
33
35 HashWriter ss{};
36 ss << *this;
37 stakeid = StakeId(ss.GetHash());
38}
39
40uint256 Stake::getHash(const StakeCommitment &commitment) const {
41 HashWriter ss{};
42 ss << commitment;
43 ss << *this;
44 return ss.GetHash();
45}
46
47bool SignedStake::verify(const StakeCommitment &commitment) const {
48 return stake.getPubkey().VerifySchnorr(stake.getHash(commitment), sig);
49}
50
51bool Proof::FromHex(Proof &proof, const std::string &hexProof,
52 bilingual_str &errorOut) {
53 if (!IsHex(hexProof)) {
54 errorOut = _("Proof must be an hexadecimal string.");
55 return false;
56 }
57
59
60 try {
61 ss >> proof;
62 } catch (std::exception &e) {
63 errorOut = strprintf(_("Proof has invalid format: %s"), e.what());
64 return false;
65 }
66
67 return true;
68}
69
70std::string Proof::ToHex() const {
72 ss << *this;
73 return HexStr(ss);
74}
75
77 HashWriter ss{};
78 ss << sequence;
79 ss << expirationTime;
81
82 WriteCompactSize(ss, stakes.size());
83 for (const SignedStake &s : stakes) {
84 ss << s.getStake();
85 }
86
87 limitedProofId = LimitedProofId(ss.GetHash());
89}
90
92 Amount total = Amount::zero();
93 for (const SignedStake &s : stakes) {
94 total += s.getStake().getAmount();
95 }
96
97 score = amountToScore(total);
98}
99
100uint32_t Proof::amountToScore(Amount amount) {
101 return (100 * amount) / COIN;
102}
103
105 return std::accumulate(stakes.begin(), stakes.end(), Amount::zero(),
106 [](const Amount current, const SignedStake &ss) {
107 return current + ss.getStake().getAmount();
108 });
109}
110
111static bool IsStandardPayoutScript(const CScript &scriptPubKey) {
112 // Check the script's standardness against the default max OP_RETURN size,
113 // so that a proof's validity is not affected by a local relay policy
114 // parameter (see -datacarriersize config option)
115 TxoutType scriptType;
116 return IsStandard(scriptPubKey, MAX_OP_RETURN_RELAY, scriptType);
117}
118
119bool Proof::verify(const Amount &stakeUtxoDustThreshold,
120 ProofValidationState &state) const {
121 if (stakes.empty()) {
122 return state.Invalid(ProofValidationResult::NO_STAKE, "no-stake");
123 }
124
125 if (stakes.size() > AVALANCHE_MAX_PROOF_STAKES) {
126 return state.Invalid(
128 strprintf("%u > %u", stakes.size(), AVALANCHE_MAX_PROOF_STAKES));
129 }
130
133 "payout-script-non-standard");
134 }
135
138 "invalid-proof-signature");
139 }
140
141 StakeId prevId = uint256::ZERO;
142 std::unordered_set<COutPoint, SaltedOutpointHasher> utxos;
143 for (const SignedStake &ss : stakes) {
144 const Stake &s = ss.getStake();
145 if (s.getAmount() < stakeUtxoDustThreshold) {
147 "amount-below-dust-threshold",
148 strprintf("%s < %s", s.getAmount().ToString(),
149 stakeUtxoDustThreshold.ToString()));
150 }
151
152 if (s.getId() < prevId) {
154 "wrong-stake-ordering");
155 }
156 prevId = s.getId();
157
158 if (!utxos.insert(s.getUTXO()).second) {
160 "duplicated-stake");
161 }
162
163 if (!ss.verify(getStakeCommitment())) {
164 return state.Invalid(
166 "invalid-stake-signature",
167 strprintf("TxId: %s", s.getUTXO().GetTxId().ToString()));
168 }
169 }
170
171 return true;
172}
173
174bool Proof::verify(const Amount &stakeUtxoDustThreshold,
175 const ChainstateManager &chainman,
176 ProofValidationState &state) const {
178 if (!verify(stakeUtxoDustThreshold, state)) {
179 // state is set by verify.
180 return false;
181 }
182
183 const CBlockIndex *activeTip = chainman.ActiveTip();
184 const int64_t tipMedianTimePast =
185 activeTip ? activeTip->GetMedianTimePast() : 0;
186 if (expirationTime > 0 && tipMedianTimePast >= expirationTime) {
187 return state.Invalid(ProofValidationResult::EXPIRED, "expired-proof");
188 }
189
190 const int64_t activeHeight = chainman.ActiveHeight();
191 const int64_t stakeUtxoMinConfirmations =
192 gArgs.GetIntArg("-avaproofstakeutxoconfirmations",
194
195 for (const SignedStake &ss : stakes) {
196 const Stake &s = ss.getStake();
197 const COutPoint &utxo = s.getUTXO();
198
199 Coin coin;
200 if (!chainman.ActiveChainstate().CoinsTip().GetCoin(utxo, coin)) {
201 // The coins are not in the UTXO set.
203 "utxo-missing-or-spent");
204 }
205
206 if ((s.getHeight() + stakeUtxoMinConfirmations - 1) > activeHeight) {
207 return state.Invalid(
209 strprintf("TxId: %s, block height: %d, chaintip height: %d",
210 s.getUTXO().GetTxId().ToString(), s.getHeight(),
211 activeHeight));
212 }
213
214 if (s.isCoinbase() != coin.IsCoinBase()) {
215 return state.Invalid(
216 ProofValidationResult::COINBASE_MISMATCH, "coinbase-mismatch",
217 strprintf("expected %s, found %s",
218 s.isCoinbase() ? "true" : "false",
219 coin.IsCoinBase() ? "true" : "false"));
220 }
221
222 if (s.getHeight() != coin.GetHeight()) {
224 "height-mismatch",
225 strprintf("expected %u, found %u",
226 s.getHeight(), coin.GetHeight()));
227 }
228
229 const CTxOut &out = coin.GetTxOut();
230 if (s.getAmount() != out.nValue) {
231 // Wrong amount.
232 return state.Invalid(
234 strprintf("expected %s, found %s", s.getAmount().ToString(),
235 out.nValue.ToString()));
236 }
237
238 CTxDestination dest;
239 if (!ExtractDestination(out.scriptPubKey, dest)) {
240 // Can't extract destination.
241 return state.Invalid(
243 "non-standard-destination");
244 }
245
246 PKHash *pkhash = std::get_if<PKHash>(&dest);
247 if (!pkhash) {
248 // Only PKHash are supported.
249 return state.Invalid(
251 "destination-type-not-supported");
252 }
253
254 const CPubKey &pubkey = s.getPubkey();
255 if (*pkhash != PKHash(pubkey)) {
256 // Wrong pubkey.
258 "destination-mismatch");
259 }
260 }
261
262 return true;
263}
264
265} // namespace avalanche
static constexpr Amount COIN
Definition: amount.h:144
ArgsManager gArgs
Definition: args.cpp:38
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
Definition: args.cpp:526
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: blockindex.h:25
int64_t GetMedianTimePast() const
Definition: blockindex.h:192
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:177
An encapsulated public key.
Definition: pubkey.h:31
bool VerifySchnorr(const uint256 &hash, const std::array< uint8_t, SCHNORR_SIZE > &sig) const
Verify a Schnorr signature (=64 bytes).
Definition: pubkey.cpp:199
An output of a transaction.
Definition: transaction.h:128
CScript scriptPubKey
Definition: transaction.h:131
Amount nValue
Definition: transaction.h:130
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition: validation.h:1219
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1435
SnapshotCompletionResult MaybeCompleteSnapshotValidation(std::function< void(bilingual_str)> shutdown_fnc=[](bilingual_str msg) { AbortNode(msg.original, msg);}) EXCLUSIVE_LOCKS_REQUIRED(Chainstate & ActiveChainstate() const
Once the background validation chainstate has reached the height which is the base of the UTXO snapsh...
int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1432
A UTXO entry.
Definition: coins.h:28
uint32_t GetHeight() const
Definition: coins.h:45
bool IsCoinBase() const
Definition: coins.h:46
CTxOut & GetTxOut()
Definition: coins.h:49
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:99
bool Invalid(Result result, const std::string &reject_reason="", const std::string &debug_message="")
Definition: validation.h:101
static bool FromHex(Proof &proof, const std::string &hexProof, bilingual_str &errorOut)
Definition: proof.cpp:51
bool verify(const Amount &stakeUtxoDustThreshold, ProofValidationState &state) const
Definition: proof.cpp:119
int64_t expirationTime
Definition: proof.h:104
void computeProofId()
Definition: proof.cpp:76
Amount getStakedAmount() const
Definition: proof.cpp:104
CScript payoutScriptPubKey
Definition: proof.h:107
std::string ToHex() const
Definition: proof.cpp:70
const StakeCommitment getStakeCommitment() const
Definition: proof.h:171
void computeScore()
Definition: proof.cpp:91
LimitedProofId limitedProofId
Definition: proof.h:110
uint64_t sequence
Definition: proof.h:103
uint32_t score
Definition: proof.h:114
std::vector< SignedStake > stakes
Definition: proof.h:106
CPubKey master
Definition: proof.h:105
ProofId proofid
Definition: proof.h:111
SchnorrSig signature
Definition: proof.h:108
static uint32_t amountToScore(Amount amount)
Definition: proof.cpp:100
SchnorrSig sig
Definition: proof.h:87
bool verify(const StakeCommitment &commitment) const
Definition: proof.cpp:47
uint256 getHash(const StakeCommitment &commitment) const
Definition: proof.cpp:40
Amount getAmount() const
Definition: proof.h:75
bool isCoinbase() const
Definition: proof.h:77
uint32_t getHeight() const
Definition: proof.h:76
StakeId stakeid
Definition: proof.h:57
void computeStakeId()
Definition: proof.cpp:34
const CPubKey & getPubkey() const
Definition: proof.h:78
const COutPoint & getUTXO() const
Definition: proof.h:74
const StakeId & getId() const
Definition: proof.h:82
uint8_t m_data[WIDTH]
Definition: uint256.h:21
const uint8_t * data() const
Definition: uint256.h:82
256-bit opaque blob.
Definition: uint256.h:129
static const uint256 ZERO
Definition: uint256.h:134
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:7
uint256 StakeId
Definition: proof.h:44
static bool IsStandardPayoutScript(const CScript &scriptPubKey)
Definition: proof.cpp:111
bool IsStandard(const CScript &scriptPubKey, const std::optional< unsigned > &max_datacarrier_bytes, TxoutType &whichType)
Definition: policy.cpp:38
static constexpr int AVALANCHE_DEFAULT_STAKE_UTXO_CONFIRMATIONS
Minimum number of confirmations before a stake utxo is mature enough to be included into a proof.
Definition: proof.h:35
static constexpr int AVALANCHE_MAX_PROOF_STAKES
How many UTXOs can be used for a single proof.
Definition: proof.h:29
@ SER_NETWORK
Definition: serialize.h:152
void WriteCompactSize(CSizeComputer &os, uint64_t nSize)
Definition: serialize.h:1254
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:158
static const unsigned int MAX_OP_RETURN_RELAY
Default setting for nMaxDatacarrierBytes.
Definition: standard.h:36
TxoutType
Definition: standard.h:38
std::variant< CNoDestination, PKHash, ScriptHash > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:85
Definition: amount.h:19
static constexpr Amount zero() noexcept
Definition: amount.h:32
std::string ToString() const
Definition: amount.cpp:22
ProofId computeProofId(const CPubKey &proofMaster) const
Definition: proofid.cpp:12
StakeCommitment(int64_t expirationTime, const CPubKey &master)
Definition: proof.cpp:25
Bilingual messages:
Definition: translation.h:17
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1202
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:68
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
template std::vector< std::byte > ParseHex(std::string_view)
bool IsHex(std::string_view str)
Returns true if each character in str is a hex character, and has an even number of hex digits.
AssertLockHeld(pool.cs)
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:11