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