Branch data Line data Source code
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 : :
6 : : #include <script/bitcoinconsensus.h>
7 : :
8 : : #include <primitives/transaction.h>
9 : : #include <pubkey.h>
10 : : #include <script/interpreter.h>
11 : : #include <version.h>
12 : :
13 : : namespace {
14 : :
15 : : /** A class that deserializes a single CTransaction one time. */
16 : : class TxInputStream
17 : : {
18 : : public:
19 : 0 : TxInputStream(int nVersionIn, const unsigned char *txTo, size_t txToLen) :
20 : 0 : m_version(nVersionIn),
21 : 0 : m_data(txTo),
22 : 0 : m_remaining(txToLen)
23 : 0 : {}
24 : :
25 : 0 : void read(Span<std::byte> dst)
26 : : {
27 [ # # ]: 0 : if (dst.size() > m_remaining) {
28 [ # # ][ # # ]: 0 : throw std::ios_base::failure(std::string(__func__) + ": end of data");
[ # # ][ # # ]
29 : : }
30 : :
31 [ # # ]: 0 : if (dst.data() == nullptr) {
32 [ # # ][ # # ]: 0 : throw std::ios_base::failure(std::string(__func__) + ": bad destination buffer");
[ # # ][ # # ]
33 : : }
34 : :
35 [ # # ]: 0 : if (m_data == nullptr) {
36 [ # # ][ # # ]: 0 : throw std::ios_base::failure(std::string(__func__) + ": bad source buffer");
[ # # ][ # # ]
37 : : }
38 : :
39 : 0 : memcpy(dst.data(), m_data, dst.size());
40 : 0 : m_remaining -= dst.size();
41 : 0 : m_data += dst.size();
42 : 0 : }
43 : :
44 : : template<typename T>
45 : 0 : TxInputStream& operator>>(T&& obj)
46 : : {
47 : 0 : ::Unserialize(*this, obj);
48 : 0 : return *this;
49 : : }
50 : :
51 : 0 : int GetVersion() const { return m_version; }
52 : : private:
53 : : const int m_version;
54 : : const unsigned char* m_data;
55 : : size_t m_remaining;
56 : : };
57 : :
58 : 0 : inline int set_error(bitcoinconsensus_error* ret, bitcoinconsensus_error serror)
59 : : {
60 [ # # ]: 0 : if (ret)
61 : 0 : *ret = serror;
62 : 0 : return 0;
63 : : }
64 : :
65 : : } // namespace
66 : :
67 : : /** Check that all specified flags are part of the libconsensus interface. */
68 : 0 : static bool verify_flags(unsigned int flags)
69 : : {
70 : 0 : return (flags & ~(bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL)) == 0;
71 : : }
72 : :
73 : 0 : static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, CAmount amount,
74 : : const unsigned char *txTo , unsigned int txToLen,
75 : : const UTXO *spentOutputs, unsigned int spentOutputsLen,
76 : : unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
77 : : {
78 [ # # ]: 0 : if (!verify_flags(flags)) {
79 : 0 : return set_error(err, bitcoinconsensus_ERR_INVALID_FLAGS);
80 : : }
81 : :
82 [ # # ][ # # ]: 0 : if (flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_TAPROOT && spentOutputs == nullptr) {
83 : 0 : return set_error(err, bitcoinconsensus_ERR_SPENT_OUTPUTS_REQUIRED);
84 : : }
85 : :
86 : : try {
87 [ # # ]: 0 : TxInputStream stream(PROTOCOL_VERSION, txTo, txToLen);
88 [ # # ]: 0 : CTransaction tx(deserialize, stream);
89 : :
90 : 0 : std::vector<CTxOut> spent_outputs;
91 [ # # ]: 0 : if (spentOutputs != nullptr) {
92 [ # # ]: 0 : if (spentOutputsLen != tx.vin.size()) {
93 [ # # ]: 0 : return set_error(err, bitcoinconsensus_ERR_SPENT_OUTPUTS_MISMATCH);
94 : : }
95 [ # # ]: 0 : for (size_t i = 0; i < spentOutputsLen; i++) {
96 [ # # ]: 0 : CScript spk = CScript(spentOutputs[i].scriptPubKey, spentOutputs[i].scriptPubKey + spentOutputs[i].scriptPubKeySize);
97 : 0 : const CAmount& value = spentOutputs[i].value;
98 [ # # ][ # # ]: 0 : CTxOut tx_out = CTxOut(value, spk);
99 [ # # ]: 0 : spent_outputs.push_back(tx_out);
100 : 0 : }
101 : 0 : }
102 : :
103 [ # # ]: 0 : if (nIn >= tx.vin.size())
104 [ # # ]: 0 : return set_error(err, bitcoinconsensus_ERR_TX_INDEX);
105 [ # # ][ # # ]: 0 : if (GetSerializeSize(tx, PROTOCOL_VERSION) != txToLen)
106 [ # # ]: 0 : return set_error(err, bitcoinconsensus_ERR_TX_SIZE_MISMATCH);
107 : :
108 : : // Regardless of the verification result, the tx did not error.
109 [ # # ]: 0 : set_error(err, bitcoinconsensus_ERR_OK);
110 : :
111 [ # # ]: 0 : PrecomputedTransactionData txdata(tx);
112 : :
113 [ # # ][ # # ]: 0 : if (spentOutputs != nullptr && flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_TAPROOT) {
114 [ # # ]: 0 : txdata.Init(tx, std::move(spent_outputs));
115 : 0 : }
116 : :
117 [ # # ][ # # ]: 0 : return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), &tx.vin[nIn].scriptWitness, flags, TransactionSignatureChecker(&tx, nIn, amount, txdata, MissingDataBehavior::FAIL), nullptr);
[ # # ]
118 [ # # ]: 0 : } catch (const std::exception&) {
119 [ # # ]: 0 : return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing
120 [ # # ]: 0 : }
121 : 0 : }
122 : :
123 : 0 : int bitcoinconsensus_verify_script_with_spent_outputs(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, int64_t amount,
124 : : const unsigned char *txTo , unsigned int txToLen,
125 : : const UTXO *spentOutputs, unsigned int spentOutputsLen,
126 : : unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
127 : : {
128 : 0 : CAmount am(amount);
129 : 0 : return ::verify_script(scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, spentOutputs, spentOutputsLen, nIn, flags, err);
130 : : }
131 : :
132 : 0 : int bitcoinconsensus_verify_script_with_amount(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, int64_t amount,
133 : : const unsigned char *txTo , unsigned int txToLen,
134 : : unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
135 : : {
136 : 0 : CAmount am(amount);
137 : 0 : UTXO *spentOutputs = nullptr;
138 : 0 : unsigned int spentOutputsLen = 0;
139 : 0 : return ::verify_script(scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, spentOutputs, spentOutputsLen, nIn, flags, err);
140 : : }
141 : :
142 : :
143 : 0 : int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
144 : : const unsigned char *txTo , unsigned int txToLen,
145 : : unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
146 : : {
147 [ # # ]: 0 : if (flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS) {
148 : 0 : return set_error(err, bitcoinconsensus_ERR_AMOUNT_REQUIRED);
149 : : }
150 : :
151 : 0 : CAmount am(0);
152 : 0 : UTXO *spentOutputs = nullptr;
153 : 0 : unsigned int spentOutputsLen = 0;
154 : 0 : return ::verify_script(scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, spentOutputs, spentOutputsLen, nIn, flags, err);
155 : 0 : }
156 : :
157 : 0 : unsigned int bitcoinconsensus_version()
158 : : {
159 : : // Just use the API version for now
160 : 0 : return BITCOINCONSENSUS_API_VER;
161 : : }
|