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 : 2221 : TxInputStream(int nVersionIn, const unsigned char *txTo, size_t txToLen) :
20 : 2221 : m_version(nVersionIn),
21 : 2221 : m_data(txTo),
22 : 2221 : m_remaining(txToLen)
23 : 2221 : {}
24 : :
25 : 7080430 : void read(Span<std::byte> dst)
26 : : {
27 [ + + ]: 7080430 : if (dst.size() > m_remaining) {
28 [ + - + - : 92 : throw std::ios_base::failure(std::string(__func__) + ": end of data");
+ - + - ]
29 : : }
30 : :
31 [ + - ]: 7080338 : if (dst.data() == nullptr) {
32 [ # # # # : 0 : throw std::ios_base::failure(std::string(__func__) + ": bad destination buffer");
# # # # ]
33 : : }
34 : :
35 [ + - ]: 7080338 : if (m_data == nullptr) {
36 [ # # # # : 0 : throw std::ios_base::failure(std::string(__func__) + ": bad source buffer");
# # # # ]
37 : : }
38 : :
39 : 7080338 : memcpy(dst.data(), m_data, dst.size());
40 : 7080338 : m_remaining -= dst.size();
41 : 7080338 : m_data += dst.size();
42 : 7080430 : }
43 : :
44 : : template<typename T>
45 : 59328 : TxInputStream& operator>>(T&& obj)
46 : : {
47 : 59328 : ::Unserialize(*this, obj);
48 : 59328 : return *this;
49 : : }
50 : :
51 : 2221 : 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 : 2652 : inline int set_error(bitcoinconsensus_error* ret, bitcoinconsensus_error serror)
59 : : {
60 [ + + ]: 2652 : if (ret)
61 : 54 : *ret = serror;
62 : 2652 : return 0;
63 : : }
64 : :
65 : : } // namespace
66 : :
67 : : /** Check that all specified flags are part of the libconsensus interface. */
68 : 2227 : static bool verify_flags(unsigned int flags)
69 : : {
70 : 2227 : return (flags & ~(bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL)) == 0;
71 : : }
72 : :
73 : 2227 : static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, CAmount amount,
74 : : const unsigned char *txTo , unsigned int txToLen,
75 : : unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
76 : : {
77 [ + + ]: 2227 : if (!verify_flags(flags)) {
78 : 6 : return set_error(err, bitcoinconsensus_ERR_INVALID_FLAGS);
79 : : }
80 : : try {
81 [ + - ]: 2221 : TxInputStream stream(PROTOCOL_VERSION, txTo, txToLen);
82 [ + + ]: 2221 : CTransaction tx(deserialize, stream);
83 [ + + ]: 2096 : if (nIn >= tx.vin.size())
84 [ + - ]: 8 : return set_error(err, bitcoinconsensus_ERR_TX_INDEX);
85 [ + - + + ]: 2088 : if (GetSerializeSize(tx, PROTOCOL_VERSION) != txToLen)
86 [ + - ]: 89 : return set_error(err, bitcoinconsensus_ERR_TX_SIZE_MISMATCH);
87 : :
88 : : // Regardless of the verification result, the tx did not error.
89 [ + - ]: 1999 : set_error(err, bitcoinconsensus_ERR_OK);
90 : :
91 [ + - ]: 1999 : PrecomputedTransactionData txdata(tx);
92 [ + - + - : 1999 : return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), &tx.vin[nIn].scriptWitness, flags, TransactionSignatureChecker(&tx, nIn, amount, txdata, MissingDataBehavior::FAIL), nullptr);
- + ]
93 [ - + ]: 2221 : } catch (const std::exception&) {
94 [ + - ]: 125 : return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing
95 [ # # ]: 125 : }
96 : 2352 : }
97 : :
98 : 1326 : int bitcoinconsensus_verify_script_with_amount(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, int64_t amount,
99 : : const unsigned char *txTo , unsigned int txToLen,
100 : : unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
101 : : {
102 : 1326 : CAmount am(amount);
103 : 1326 : return ::verify_script(scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, nIn, flags, err);
104 : : }
105 : :
106 : :
107 : 1326 : int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
108 : : const unsigned char *txTo , unsigned int txToLen,
109 : : unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
110 : : {
111 [ + + ]: 1326 : if (flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS) {
112 : 425 : return set_error(err, bitcoinconsensus_ERR_AMOUNT_REQUIRED);
113 : : }
114 : :
115 : 901 : CAmount am(0);
116 : 901 : return ::verify_script(scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, nIn, flags, err);
117 : 1326 : }
118 : :
119 : 1327 : unsigned int bitcoinconsensus_version()
120 : : {
121 : : // Just use the API version for now
122 : 1327 : return BITCOINCONSENSUS_API_VER;
123 : : }
|