@@ -65,6 +65,7 @@ class CTxIn
6565 COutPoint prevout;
6666 CScript scriptSig;
6767 uint32_t nSequence;
68+ CScriptWitness scriptWitness; // ! Only serialized through CTxInWitnessSerializer
6869
6970 /* Setting nSequence to this value for every input in a transaction
7071 * disables nLockTime. */
@@ -125,6 +126,33 @@ class CTxIn
125126 std::string ToString () const ;
126127};
127128
129+ class CTxInsWitnessSerializer
130+ {
131+ private:
132+ std::vector<CTxIn>* ptr;
133+
134+ public:
135+ CTxInsWitnessSerializer (std::vector<CTxIn>* txin) : ptr(txin) {}
136+
137+ ADD_SERIALIZE_METHODS;
138+
139+ template <typename Stream, typename Operation>
140+ inline void SerializationOp (Stream& s, Operation ser_action, int nType, int nVersion) {
141+ for (unsigned int i = 0 ; i < ptr->size (); i++) {
142+ READWRITE ((*ptr)[i].scriptWitness .stack );
143+ }
144+ }
145+
146+ bool IsNull () {
147+ for (unsigned int i = 0 ; i < ptr->size (); i++) {
148+ if (!(*ptr)[i].scriptWitness .IsNull ()) {
149+ return false ;
150+ }
151+ }
152+ return true ;
153+ }
154+ };
155+
128156/* * An output of a transaction. It contains the public key that the next input
129157 * must be able to sign with to claim it.
130158 */
@@ -213,62 +241,6 @@ class CTxOut
213241 std::string ToString () const ;
214242};
215243
216- class CTxInWitness
217- {
218- public:
219- CScriptWitness scriptWitness;
220-
221- ADD_SERIALIZE_METHODS;
222-
223- template <typename Stream, typename Operation>
224- inline void SerializationOp (Stream& s, Operation ser_action, int nType, int nVersion)
225- {
226- READWRITE (scriptWitness.stack );
227- }
228-
229- bool IsNull () const { return scriptWitness.IsNull (); }
230-
231- CTxInWitness () { }
232- };
233-
234- class CTxWitness
235- {
236- public:
237- /* * In case vtxinwit is missing, all entries are treated as if they were empty CTxInWitnesses */
238- std::vector<CTxInWitness> vtxinwit;
239-
240- ADD_SERIALIZE_METHODS;
241-
242- bool IsEmpty () const { return vtxinwit.empty (); }
243-
244- bool IsNull () const
245- {
246- for (size_t n = 0 ; n < vtxinwit.size (); n++) {
247- if (!vtxinwit[n].IsNull ()) {
248- return false ;
249- }
250- }
251- return true ;
252- }
253-
254- void SetNull ()
255- {
256- vtxinwit.clear ();
257- }
258-
259- template <typename Stream, typename Operation>
260- inline void SerializationOp (Stream& s, Operation ser_action, int nType, int nVersion)
261- {
262- for (size_t n = 0 ; n < vtxinwit.size (); n++) {
263- READWRITE (vtxinwit[n]);
264- }
265- if (IsNull ()) {
266- /* It's illegal to encode a witness when all vtxinwit entries are empty. */
267- throw std::ios_base::failure (" Superfluous witness record" );
268- }
269- }
270- };
271-
272244struct CMutableTransaction ;
273245
274246/* *
@@ -297,7 +269,6 @@ inline void SerializeTransaction(TxType& tx, Stream& s, Operation ser_action, in
297269 if (ser_action.ForRead ()) {
298270 tx.vin .clear ();
299271 tx.vout .clear ();
300- tx.wit .SetNull ();
301272 /* Try to read the vin. In case the dummy is there, this will be read as an empty vector. */
302273 READWRITE (tx.vin );
303274 if (tx.vin .size () == 0 && fAllowWitness ) {
@@ -314,19 +285,22 @@ inline void SerializeTransaction(TxType& tx, Stream& s, Operation ser_action, in
314285 if ((flags & 1 ) && fAllowWitness ) {
315286 /* The witness flag is present, and we support witnesses. */
316287 flags ^= 1 ;
317- tx.wit .vtxinwit .resize (tx.vin .size ());
318- READWRITE (tx.wit );
288+ CTxInsWitnessSerializer ser (&tx.vin );
289+ READWRITE (ser);
290+ if (ser.IsNull ()) {
291+ /* It's illegal to encode a witness when all vtxinwit entries are empty. */
292+ throw std::ios_base::failure (" Superfluous witness record" );
293+ }
319294 }
320295 if (flags) {
321296 /* Unknown flag in the serialization */
322297 throw std::ios_base::failure (" Unknown transaction optional data" );
323298 }
324299 } else {
325300 // Consistency check
326- assert (tx.wit .vtxinwit .size () <= tx.vin .size ());
327301 if (fAllowWitness ) {
328302 /* Check whether witnesses need to be serialized. */
329- if (! tx.wit . IsNull ()) {
303+ if (tx.HasWitness ()) {
330304 flags |= 1 ;
331305 }
332306 }
@@ -339,8 +313,8 @@ inline void SerializeTransaction(TxType& tx, Stream& s, Operation ser_action, in
339313 READWRITE (tx.vin );
340314 READWRITE (tx.vout );
341315 if (flags & 1 ) {
342- tx. wit . vtxinwit . resize ( tx.vin . size () );
343- READWRITE (tx. wit );
316+ CTxInsWitnessSerializer ser (& tx.vin );
317+ READWRITE (ser );
344318 }
345319 }
346320 READWRITE (tx.nLockTime );
@@ -376,7 +350,6 @@ class CTransaction
376350 int32_t nVersion;
377351 std::vector<CTxIn> vin;
378352 std::vector<CTxOut> vout;
379- CTxWitness wit;
380353 uint32_t nLockTime;
381354
382355 /* * Construct a CTransaction that qualifies as IsNull() */
@@ -437,6 +410,8 @@ class CTransaction
437410 std::string ToString () const ;
438411
439412 void UpdateHash ();
413+
414+ bool HasWitness () const { return !CTxInsWitnessSerializer (const_cast <std::vector<CTxIn>*>(&vin)).IsNull (); }
440415};
441416
442417/* * A mutable version of CTransaction. */
@@ -445,7 +420,6 @@ struct CMutableTransaction
445420 int32_t nVersion;
446421 std::vector<CTxIn> vin;
447422 std::vector<CTxOut> vout;
448- CTxWitness wit;
449423 uint32_t nLockTime;
450424
451425 CMutableTransaction ();
@@ -462,6 +436,8 @@ struct CMutableTransaction
462436 * fly, as opposed to GetHash() in CTransaction, which uses a cached result.
463437 */
464438 uint256 GetHash () const ;
439+
440+ bool HasWitness () const { return !CTxInsWitnessSerializer (const_cast <std::vector<CTxIn>*>(&vin)).IsNull (); }
465441};
466442
467443/* * Compute the weight of a transaction, as defined by BIP 141 */
0 commit comments