Bitcoin ABC  0.24.7
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 
7 #include <avalanche/validation.h>
8 #include <coins.h>
9 #include <hash.h>
10 #include <policy/policy.h>
11 #include <script/standard.h>
12 #include <streams.h>
13 #include <util/strencodings.h>
14 #include <util/system.h>
15 #include <util/translation.h>
16 
17 #include <tinyformat.h>
18 
19 #include <unordered_set>
20 
21 namespace avalanche {
22 
23 StakeCommitment::StakeCommitment(const ProofId &proofid, int64_t expirationTime,
24  const CPubKey &master) {
25  if (Proof::useLegacy(gArgs)) {
26  memcpy(m_data, proofid.data(), sizeof(m_data));
27  } else {
28  CHashWriter ss(SER_GETHASH, 0);
29  ss << expirationTime;
30  ss << master;
31  const uint256 &hash = ss.GetHash();
32  memcpy(m_data, hash.data(), sizeof(m_data));
33  }
34 }
35 
37  CHashWriter ss(SER_GETHASH, 0);
38  ss << *this;
39  stakeid = StakeId(ss.GetHash());
40 }
41 
42 uint256 Stake::getHash(const StakeCommitment &commitment) const {
43  CHashWriter ss(SER_GETHASH, 0);
44  ss << commitment;
45  ss << *this;
46  return ss.GetHash();
47 }
48 
49 bool SignedStake::verify(const StakeCommitment &commitment) const {
50  return stake.getPubkey().VerifySchnorr(stake.getHash(commitment), sig);
51 }
52 
54  return useLegacy(gArgs);
55 }
56 
57 bool Proof::useLegacy(const ArgsManager &argsman) {
58  return argsman.GetBoolArg("-legacyavaproof",
60 }
61 
62 bool Proof::FromHex(Proof &proof, const std::string &hexProof,
63  bilingual_str &errorOut) {
64  if (!IsHex(hexProof)) {
65  errorOut = _("Proof must be an hexadecimal string.");
66  return false;
67  }
68 
70 
71  try {
72  ss >> proof;
73  } catch (std::exception &e) {
74  errorOut = strprintf(_("Proof has invalid format: %s"), e.what());
75  return false;
76  }
77 
78  return true;
79 }
80 
82  CHashWriter ss(SER_GETHASH, 0);
83  ss << sequence;
84  ss << expirationTime;
85  if (!useLegacy(gArgs)) {
86  ss << payoutScriptPubKey;
87  }
88 
89  WriteCompactSize(ss, stakes.size());
90  for (const SignedStake &s : stakes) {
91  ss << s.getStake();
92  }
93 
96 }
97 
98 uint32_t Proof::getScore() const {
99  Amount total = Amount::zero();
100  for (const SignedStake &s : stakes) {
101  total += s.getStake().getAmount();
102  }
103 
104  return uint32_t((100 * total) / COIN);
105 }
106 
108  if (stakes.empty()) {
109  return state.Invalid(ProofValidationResult::NO_STAKE, "no-stake");
110  }
111 
112  if (stakes.size() > AVALANCHE_MAX_PROOF_STAKES) {
113  return state.Invalid(
114  ProofValidationResult::TOO_MANY_UTXOS, "too-many-utxos",
115  strprintf("%u > %u", stakes.size(), AVALANCHE_MAX_PROOF_STAKES));
116  }
117 
118  if (!useLegacy(gArgs)) {
119  TxoutType scriptType;
120  if (!IsStandard(payoutScriptPubKey, scriptType)) {
122  "payout-script-non-standard");
123  }
124 
127  "invalid-proof-signature");
128  }
129  }
130 
131  StakeId prevId = uint256::ZERO;
132  std::unordered_set<COutPoint, SaltedOutpointHasher> utxos;
133  for (const SignedStake &ss : stakes) {
134  const Stake &s = ss.getStake();
135  if (s.getAmount() < PROOF_DUST_THRESHOLD) {
137  "amount-below-dust-threshold",
138  strprintf("%s < %s", s.getAmount().ToString(),
140  }
141 
142  if (s.getId() < prevId) {
144  "wrong-stake-ordering");
145  }
146  prevId = s.getId();
147 
148  if (!utxos.insert(s.getUTXO()).second) {
150  "duplicated-stake");
151  }
152 
153  if (!ss.verify(getStakeCommitment())) {
154  return state.Invalid(
156  "invalid-stake-signature",
157  strprintf("TxId: %s", s.getUTXO().GetTxId().ToString()));
158  }
159  }
160 
161  return true;
162 }
163 
164 bool Proof::verify(ProofValidationState &state, const CCoinsView &view) const {
165  if (!verify(state)) {
166  // state is set by verify.
167  return false;
168  }
169 
170  for (const SignedStake &ss : stakes) {
171  const Stake &s = ss.getStake();
172  const COutPoint &utxo = s.getUTXO();
173 
174  Coin coin;
175  if (!view.GetCoin(utxo, coin)) {
176  // The coins are not in the UTXO set.
178  "utxo-missing-or-spent");
179  }
180 
181  if (s.isCoinbase() != coin.IsCoinBase()) {
182  return state.Invalid(
183  ProofValidationResult::COINBASE_MISMATCH, "coinbase-mismatch",
184  strprintf("expected %s, found %s",
185  s.isCoinbase() ? "true" : "false",
186  coin.IsCoinBase() ? "true" : "false"));
187  }
188 
189  if (s.getHeight() != coin.GetHeight()) {
191  "height-mismatch",
192  strprintf("expected %u, found %u",
193  s.getHeight(), coin.GetHeight()));
194  }
195 
196  const CTxOut &out = coin.GetTxOut();
197  if (s.getAmount() != out.nValue) {
198  // Wrong amount.
199  return state.Invalid(
200  ProofValidationResult::AMOUNT_MISMATCH, "amount-mismatch",
201  strprintf("expected %s, found %s", s.getAmount().ToString(),
202  out.nValue.ToString()));
203  }
204 
205  CTxDestination dest;
206  if (!ExtractDestination(out.scriptPubKey, dest)) {
207  // Can't extract destination.
208  return state.Invalid(
210  "non-standard-destination");
211  }
212 
213  PKHash *pkhash = boost::get<PKHash>(&dest);
214  if (!pkhash) {
215  // Only PKHash are supported.
216  return state.Invalid(
218  "destination-type-not-supported");
219  }
220 
221  const CPubKey &pubkey = s.getPubkey();
222  if (*pkhash != PKHash(pubkey)) {
223  // Wrong pubkey.
225  "destination-mismatch");
226  }
227  }
228 
229  return true;
230 }
231 
232 } // namespace avalanche
avalanche::SignedStake::sig
SchnorrSig sig
Definition: proof.h:87
policy.h
avalanche::Stake::stakeid
StakeId stakeid
Definition: proof.h:57
CTxOut::nValue
Amount nValue
Definition: transaction.h:132
Amount::ToString
std::string ToString() const
Definition: amount.cpp:23
avalanche::ProofValidationResult::DESTINATION_MISMATCH
@ DESTINATION_MISMATCH
ArgsManager::GetBoolArg
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: system.cpp:517
avalanche::PROOF_DUST_THRESHOLD
static constexpr Amount PROOF_DUST_THRESHOLD
Minimum amount per utxo.
Definition: proof.h:37
_
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:55
ParseHex
std::vector< uint8_t > ParseHex(const char *psz)
Definition: strencodings.cpp:87
avalanche::Proof::computeProofId
void computeProofId()
Definition: proof.cpp:81
avalanche::ProofValidationResult::DESTINATION_NOT_SUPPORTED
@ DESTINATION_NOT_SUPPORTED
avalanche::Proof::sequence
uint64_t sequence
Definition: proof.h:103
avalanche::StakeId
uint256 StakeId
Definition: proof.h:41
avalanche::ProofValidationResult::NO_STAKE
@ NO_STAKE
IsStandard
bool IsStandard(const CScript &scriptPubKey, TxoutType &whichType)
Definition: policy.cpp:38
TxoutType
TxoutType
Definition: standard.h:85
streams.h
avalanche::Stake::getHash
uint256 getHash(const StakeCommitment &commitment) const
Definition: proof.cpp:42
avalanche
Definition: avalanche.h:11
CPubKey::VerifySchnorr
bool VerifySchnorr(const uint256 &hash, const std::array< uint8_t, SCHNORR_SIZE > &sig) const
Verify a Schnorr signature (=64 bytes).
Definition: pubkey.cpp:200
avalanche::SignedStake::stake
Stake stake
Definition: proof.h:86
bilingual_str
Bilingual messages:
Definition: translation.h:17
avalanche::ProofValidationResult::HEIGHT_MISMATCH
@ HEIGHT_MISMATCH
IsHex
bool IsHex(const std::string &str)
Returns true if each character in str is a hex character, and has an even number of hex digits.
Definition: strencodings.cpp:64
avalanche::Stake::isCoinbase
bool isCoinbase() const
Definition: proof.h:77
avalanche::Proof::stakes
std::vector< SignedStake > stakes
Definition: proof.h:106
avalanche::SignedStake
Definition: proof.h:85
avalanche::ProofId
Definition: proofid.h:17
AVALANCHE_DEFAULT_LEGACY_PROOF
static constexpr bool AVALANCHE_DEFAULT_LEGACY_PROOF
Whether the legacy proof format should be used by default.
Definition: proof.h:32
avalanche::ProofValidationResult::NON_STANDARD_DESTINATION
@ NON_STANDARD_DESTINATION
avalanche::ProofValidationResult::INVALID_STAKE_SIGNATURE
@ INVALID_STAKE_SIGNATURE
base_blob< 256 >::m_data
uint8_t m_data[WIDTH]
Definition: uint256.h:19
COIN
static constexpr Amount COIN
Definition: amount.h:154
CCoinsView::GetCoin
virtual bool GetCoin(const COutPoint &outpoint, Coin &coin) const
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition: coins.cpp:12
tinyformat.h
Amount::zero
static constexpr Amount zero()
Definition: amount.h:42
avalanche::ProofValidationResult::DUST_THRESOLD
@ DUST_THRESOLD
avalanche::Proof::payoutScriptPubKey
CScript payoutScriptPubKey
Definition: proof.h:107
avalanche::Stake::getUTXO
const COutPoint & getUTXO() const
Definition: proof.h:74
SER_NETWORK
@ SER_NETWORK
Definition: serialize.h:165
CCoinsView
Abstract view on the open txout dataset.
Definition: coins.h:175
validation.h
avalanche::Stake
Definition: proof.h:50
strencodings.h
avalanche::Proof::expirationTime
int64_t expirationTime
Definition: proof.h:104
COutPoint::GetTxId
const TxId & GetTxId() const
Definition: transaction.h:37
avalanche::ProofValidationResult::AMOUNT_MISMATCH
@ AMOUNT_MISMATCH
avalanche::StakeCommitment
Definition: proof.h:43
avalanche::Stake::getPubkey
const CPubKey & getPubkey() const
Definition: proof.h:78
CTxOut
An output of a transaction.
Definition: transaction.h:130
Coin
A UTXO entry.
Definition: coins.h:27
avalanche::Stake::getAmount
Amount getAmount() const
Definition: proof.h:75
avalanche::ProofValidationState
Definition: validation.h:33
CTxOut::scriptPubKey
CScript scriptPubKey
Definition: transaction.h:133
avalanche::Proof::proofid
ProofId proofid
Definition: proof.h:111
avalanche::Stake::getHeight
uint32_t getHeight() const
Definition: proof.h:76
WriteCompactSize
void WriteCompactSize(CSizeComputer &os, uint64_t nSize)
Definition: serialize.h:1178
standard.h
avalanche::SignedStake::verify
bool verify(const StakeCommitment &commitment) const
Definition: proof.cpp:49
avalanche::Proof::getScore
uint32_t getScore() const
Definition: proof.cpp:98
AVALANCHE_MAX_PROOF_STAKES
static constexpr int AVALANCHE_MAX_PROOF_STAKES
How many UTXOs can be used for a single proof.
Definition: proof.h:27
uint256::ZERO
static const uint256 ZERO
Definition: uint256.h:132
avalanche::Stake::computeStakeId
void computeStakeId()
Definition: proof.cpp:36
avalanche::ProofValidationResult::DUPLICATE_STAKE
@ DUPLICATE_STAKE
avalanche::Proof::useLegacy
static bool useLegacy()
Definition: proof.cpp:53
avalanche::StakeCommitment::StakeCommitment
StakeCommitment()
Definition: proof.h:44
base_blob::ToString
std::string ToString() const
Definition: uint256.h:78
uint256
256-bit opaque blob.
Definition: uint256.h:127
avalanche::LimitedProofId
Definition: proofid.h:28
Amount
Definition: amount.h:19
avalanche::Proof::master
CPubKey master
Definition: proof.h:105
avalanche::ProofValidationResult::INVALID_PAYOUT_SCRIPT
@ INVALID_PAYOUT_SCRIPT
ExtractDestination
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:161
ValidationState::Invalid
bool Invalid(Result result, const std::string &reject_reason="", const std::string &debug_message="")
Definition: validation.h:100
coins.h
avalanche::Proof
Definition: proof.h:102
avalanche::Proof::FromHex
static bool FromHex(Proof &proof, const std::string &hexProof, bilingual_str &errorOut)
Definition: proof.cpp:62
avalanche::ProofValidationResult::MISSING_UTXO
@ MISSING_UTXO
system.h
PKHash
Definition: standard.h:106
strprintf
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1201
SER_GETHASH
@ SER_GETHASH
Definition: serialize.h:167
CPubKey
An encapsulated public key.
Definition: pubkey.h:31
ArgsManager
Definition: system.h:152
avalanche::ProofValidationResult::WRONG_STAKE_ORDERING
@ WRONG_STAKE_ORDERING
translation.h
proof.h
gArgs
ArgsManager gArgs
Definition: system.cpp:75
avalanche::Proof::signature
SchnorrSig signature
Definition: proof.h:108
CHashWriter
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:99
avalanche::ProofValidationResult::TOO_MANY_UTXOS
@ TOO_MANY_UTXOS
avalanche::ProofValidationResult::COINBASE_MISMATCH
@ COINBASE_MISMATCH
Coin::GetHeight
uint32_t GetHeight() const
Definition: coins.h:44
avalanche::Stake::getId
const StakeId & getId() const
Definition: proof.h:82
avalanche::Proof::getStakeCommitment
const StakeCommitment getStakeCommitment() const
Definition: proof.h:154
avalanche::LimitedProofId::computeProofId
ProofId computeProofId(const CPubKey &proofMaster) const
Definition: proofid.cpp:12
CDataStream
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:197
avalanche::ProofValidationResult::INVALID_PROOF_SIGNATURE
@ INVALID_PROOF_SIGNATURE
COutPoint
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:22
CHashWriter::GetHash
uint256 GetHash()
Definition: hash.h:118
avalanche::Proof::verify
bool verify(ProofValidationState &state) const
Definition: proof.cpp:107
Coin::GetTxOut
CTxOut & GetTxOut()
Definition: coins.h:48
CTxDestination
boost::variant< CNoDestination, PKHash, ScriptHash > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:132
base_blob::data
const uint8_t * data() const
Definition: uint256.h:80
PROTOCOL_VERSION
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:11
Coin::IsCoinBase
bool IsCoinBase() const
Definition: coins.h:45
avalanche::Proof::limitedProofId
LimitedProofId limitedProofId
Definition: proof.h:110