Bitcoin Core  27.99.0
P2P Digital Currency
bitcoinconsensus.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2022 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
7 
9 #include <pubkey.h>
10 #include <script/interpreter.h>
11 
12 namespace {
13 
15 class TxInputStream
16 {
17 public:
18  TxInputStream(const unsigned char *txTo, size_t txToLen) :
19  m_data(txTo),
20  m_remaining(txToLen)
21  {}
22 
23  void read(Span<std::byte> dst)
24  {
25  if (dst.size() > m_remaining) {
26  throw std::ios_base::failure(std::string(__func__) + ": end of data");
27  }
28 
29  if (dst.data() == nullptr) {
30  throw std::ios_base::failure(std::string(__func__) + ": bad destination buffer");
31  }
32 
33  if (m_data == nullptr) {
34  throw std::ios_base::failure(std::string(__func__) + ": bad source buffer");
35  }
36 
37  memcpy(dst.data(), m_data, dst.size());
38  m_remaining -= dst.size();
39  m_data += dst.size();
40  }
41 
42  template<typename T>
43  TxInputStream& operator>>(T&& obj)
44  {
45  ::Unserialize(*this, obj);
46  return *this;
47  }
48 
49 private:
50  const unsigned char* m_data;
51  size_t m_remaining;
52 };
53 
54 inline int set_error(bitcoinconsensus_error* ret, bitcoinconsensus_error serror)
55 {
56  if (ret)
57  *ret = serror;
58  return 0;
59 }
60 
61 } // namespace
62 
64 static bool verify_flags(unsigned int flags)
65 {
67 }
68 
69 static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, CAmount amount,
70  const unsigned char *txTo , unsigned int txToLen,
71  const UTXO *spentOutputs, unsigned int spentOutputsLen,
72  unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
73 {
74  if (!verify_flags(flags)) {
75  return set_error(err, bitcoinconsensus_ERR_INVALID_FLAGS);
76  }
77 
78  if (flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_TAPROOT && spentOutputs == nullptr) {
79  return set_error(err, bitcoinconsensus_ERR_SPENT_OUTPUTS_REQUIRED);
80  }
81 
82  try {
83  TxInputStream stream(txTo, txToLen);
85 
86  std::vector<CTxOut> spent_outputs;
87  if (spentOutputs != nullptr) {
88  if (spentOutputsLen != tx.vin.size()) {
89  return set_error(err, bitcoinconsensus_ERR_SPENT_OUTPUTS_MISMATCH);
90  }
91  for (size_t i = 0; i < spentOutputsLen; i++) {
92  CScript spk = CScript(spentOutputs[i].scriptPubKey, spentOutputs[i].scriptPubKey + spentOutputs[i].scriptPubKeySize);
93  const CAmount& value = spentOutputs[i].value;
94  CTxOut tx_out = CTxOut(value, spk);
95  spent_outputs.push_back(tx_out);
96  }
97  }
98 
99  if (nIn >= tx.vin.size())
100  return set_error(err, bitcoinconsensus_ERR_TX_INDEX);
101  if (GetSerializeSize(TX_WITH_WITNESS(tx)) != txToLen)
102  return set_error(err, bitcoinconsensus_ERR_TX_SIZE_MISMATCH);
103 
104  // Regardless of the verification result, the tx did not error.
105  set_error(err, bitcoinconsensus_ERR_OK);
106 
107  PrecomputedTransactionData txdata(tx);
108 
109  if (spentOutputs != nullptr && flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_TAPROOT) {
110  txdata.Init(tx, std::move(spent_outputs));
111  }
112 
113  return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), &tx.vin[nIn].scriptWitness, flags, TransactionSignatureChecker(&tx, nIn, amount, txdata, MissingDataBehavior::FAIL), nullptr);
114  } catch (const std::exception&) {
115  return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing
116  }
117 }
118 
119 int bitcoinconsensus_verify_script_with_spent_outputs(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, int64_t amount,
120  const unsigned char *txTo , unsigned int txToLen,
121  const UTXO *spentOutputs, unsigned int spentOutputsLen,
122  unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
123 {
124  CAmount am(amount);
125  return ::verify_script(scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, spentOutputs, spentOutputsLen, nIn, flags, err);
126 }
127 
128 int bitcoinconsensus_verify_script_with_amount(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, int64_t amount,
129  const unsigned char *txTo , unsigned int txToLen,
130  unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
131 {
132  CAmount am(amount);
133  UTXO *spentOutputs = nullptr;
134  unsigned int spentOutputsLen = 0;
135  return ::verify_script(scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, spentOutputs, spentOutputsLen, nIn, flags, err);
136 }
137 
138 
139 int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
140  const unsigned char *txTo , unsigned int txToLen,
141  unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
142 {
144  return set_error(err, bitcoinconsensus_ERR_AMOUNT_REQUIRED);
145  }
146 
147  CAmount am(0);
148  UTXO *spentOutputs = nullptr;
149  unsigned int spentOutputsLen = 0;
150  return ::verify_script(scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, spentOutputs, spentOutputsLen, nIn, flags, err);
151 }
152 
154 {
155  // Just use the API version for now
157 }
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
int ret
int flags
Definition: bitcoin-tx.cpp:530
static bool verify_flags(unsigned int flags)
Check that all specified flags are part of the libconsensus interface.
unsigned int bitcoinconsensus_version()
int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, const unsigned char *txTo, unsigned int txToLen, unsigned int nIn, unsigned int flags, bitcoinconsensus_error *err)
Returns 1 if the input nIn of the serialized transaction pointed to by txTo correctly spends the scri...
int bitcoinconsensus_verify_script_with_amount(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, int64_t amount, const unsigned char *txTo, unsigned int txToLen, unsigned int nIn, unsigned int flags, bitcoinconsensus_error *err)
int bitcoinconsensus_verify_script_with_spent_outputs(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, int64_t amount, const unsigned char *txTo, unsigned int txToLen, const UTXO *spentOutputs, unsigned int spentOutputsLen, unsigned int nIn, unsigned int flags, bitcoinconsensus_error *err)
static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, CAmount amount, const unsigned char *txTo, unsigned int txToLen, const UTXO *spentOutputs, unsigned int spentOutputsLen, unsigned int nIn, unsigned int flags, bitcoinconsensus_error *err)
enum bitcoinconsensus_error_t bitcoinconsensus_error
@ bitcoinconsensus_ERR_OK
@ bitcoinconsensus_ERR_SPENT_OUTPUTS_MISMATCH
@ bitcoinconsensus_ERR_TX_DESERIALIZE
@ bitcoinconsensus_ERR_AMOUNT_REQUIRED
@ bitcoinconsensus_ERR_TX_INDEX
@ bitcoinconsensus_ERR_INVALID_FLAGS
@ bitcoinconsensus_ERR_TX_SIZE_MISMATCH
@ bitcoinconsensus_ERR_SPENT_OUTPUTS_REQUIRED
@ bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL
@ bitcoinconsensus_SCRIPT_FLAGS_VERIFY_TAPROOT
@ bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS
#define BITCOINCONSENSUS_API_VER
QDataStream & operator>>(QDataStream &in, BitcoinUnit &unit)
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:414
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:296
const std::vector< CTxIn > vin
Definition: transaction.h:306
An output of a transaction.
Definition: transaction.h:150
A Span is an object that can refer to a contiguous sequence of objects.
Definition: span.h:98
constexpr std::size_t size() const noexcept
Definition: span.h:187
constexpr C * data() const noexcept
Definition: span.h:174
bool VerifyScript(const CScript &scriptSig, const CScript &scriptPubKey, const CScriptWitness *witness, unsigned int flags, const BaseSignatureChecker &checker, ScriptError *serror)
@ FAIL
Just act as if the signature was invalid.
static constexpr TransactionSerParams TX_WITH_WITNESS
Definition: transaction.h:195
size_t GetSerializeSize(const T &t)
Definition: serialize.h:1116
constexpr deserialize_type deserialize
Definition: serialize.h:49
void Unserialize(Stream &, V)=delete
void Init(const T &tx, std::vector< CTxOut > &&spent_outputs, bool force=false)
Initialize this PrecomputedTransactionData with transaction data.
int64_t value