bitcoinconsensus.cpp
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 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 63 /** Check that all specified flags are part of the libconsensus interface. */ 64 static bool verify_flags(unsigned int flags) 65 { 66 return (flags & ~(bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL)) == 0; 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); 84 CTransaction tx(deserialize, TX_WITH_WITNESS, stream); 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 { 143 if (flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS) { 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 153 unsigned int bitcoinconsensus_version() 154 { 155 // Just use the API version for now 156 return BITCOINCONSENSUS_API_VER; 157 }