1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2015 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 "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:
TxInputStream(int nTypeIn,int nVersionIn,const unsigned char * txTo,size_t txToLen)19 TxInputStream(int nTypeIn, int nVersionIn, const unsigned char *txTo, size_t txToLen) :
20 m_type(nTypeIn),
21 m_version(nVersionIn),
22 m_data(txTo),
23 m_remaining(txToLen)
24 {}
25
read(char * pch,size_t nSize)26 TxInputStream& read(char* pch, size_t nSize)
27 {
28 if (nSize > m_remaining)
29 throw std::ios_base::failure(std::string(__func__) + ": end of data");
30
31 if (pch == NULL)
32 throw std::ios_base::failure(std::string(__func__) + ": bad destination buffer");
33
34 if (m_data == NULL)
35 throw std::ios_base::failure(std::string(__func__) + ": bad source buffer");
36
37 memcpy(pch, m_data, nSize);
38 m_remaining -= nSize;
39 m_data += nSize;
40 return *this;
41 }
42
43 template<typename T>
operator >>(T & obj)44 TxInputStream& operator>>(T& obj)
45 {
46 ::Unserialize(*this, obj, m_type, m_version);
47 return *this;
48 }
49
50 private:
51 const int m_type;
52 const int m_version;
53 const unsigned char* m_data;
54 size_t m_remaining;
55 };
56
set_error(bitcoinconsensus_error * ret,bitcoinconsensus_error serror)57 inline int set_error(bitcoinconsensus_error* ret, bitcoinconsensus_error serror)
58 {
59 if (ret)
60 *ret = serror;
61 return 0;
62 }
63
64 struct ECCryptoClosure
65 {
66 ECCVerifyHandle handle;
67 };
68
69 ECCryptoClosure instance_of_eccryptoclosure;
70 }
71
verify_script(const unsigned char * scriptPubKey,unsigned int scriptPubKeyLen,CAmount amount,const unsigned char * txTo,unsigned int txToLen,unsigned int nIn,unsigned int flags,bitcoinconsensus_error * err)72 static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, CAmount amount,
73 const unsigned char *txTo , unsigned int txToLen,
74 unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
75 {
76 try {
77 TxInputStream stream(SER_NETWORK, PROTOCOL_VERSION, txTo, txToLen);
78 CTransaction tx;
79 stream >> tx;
80 if (nIn >= tx.vin.size())
81 return set_error(err, bitcoinconsensus_ERR_TX_INDEX);
82 if (tx.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION) != txToLen)
83 return set_error(err, bitcoinconsensus_ERR_TX_SIZE_MISMATCH);
84
85 // Regardless of the verification result, the tx did not error.
86 set_error(err, bitcoinconsensus_ERR_OK);
87 PrecomputedTransactionData txdata(tx);
88 return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), nIn < tx.wit.vtxinwit.size() ? &tx.wit.vtxinwit[nIn].scriptWitness : NULL, flags, TransactionSignatureChecker(&tx, nIn, amount, txdata), NULL);
89 } catch (const std::exception&) {
90 return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing
91 }
92 }
93
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)94 int bitcoinconsensus_verify_script_with_amount(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, int64_t amount,
95 const unsigned char *txTo , unsigned int txToLen,
96 unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
97 {
98 CAmount am(amount);
99 return ::verify_script(scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, nIn, flags, err);
100 }
101
102
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)103 int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
104 const unsigned char *txTo , unsigned int txToLen,
105 unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
106 {
107 if (flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS) {
108 return set_error(err, bitcoinconsensus_ERR_AMOUNT_REQUIRED);
109 }
110
111 CAmount am(0);
112 return ::verify_script(scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, nIn, flags, err);
113 }
114
bitcoinconsensus_version()115 unsigned int bitcoinconsensus_version()
116 {
117 // Just use the API version for now
118 return BITCOINCONSENSUS_API_VER;
119 }
120