Skip to content

Commit cb2c7fd

Browse files
committed
Replace CTxInUndo with Coin
The earlier CTxInUndo class now holds the same information as the Coin class. Instead of duplicating functionality, replace CTxInUndo with a serialization adapter for Coin.
1 parent 422634e commit cb2c7fd

File tree

3 files changed

+63
-36
lines changed

3 files changed

+63
-36
lines changed

src/test/coins_tests.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
#include <boost/test/unit_test.hpp>
1919

20-
int ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const COutPoint& out);
20+
int ApplyTxInUndo(const Coin& undo, CCoinsViewCache& view, const COutPoint& out);
2121
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight);
2222

2323
namespace
@@ -371,7 +371,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
371371
// restore inputs
372372
if (!tx.IsCoinBase()) {
373373
const COutPoint &out = tx.vin[0].prevout;
374-
const CTxInUndo &undoin = undo.vprevout[0];
374+
const Coin &undoin = undo.vprevout[0];
375375
ApplyTxInUndo(undoin, *(stack.back()), out);
376376
}
377377
// Store as a candidate for reconnection

src/undo.h

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,61 +7,90 @@
77
#define BITCOIN_UNDO_H
88

99
#include "compressor.h"
10+
#include "consensus/consensus.h"
1011
#include "primitives/transaction.h"
1112
#include "serialize.h"
1213

1314
/** Undo information for a CTxIn
1415
*
1516
* Contains the prevout's CTxOut being spent, and its metadata as well
16-
* (coinbase or not, height). Earlier versions also stored the transaction
17-
* version.
17+
* (coinbase or not, height). The serialization contains a dummy value of
18+
* zero. This is be compatible with older versions which expect to see
19+
* the transaction version there.
1820
*/
19-
class CTxInUndo
21+
class TxInUndoSerializer
2022
{
21-
public:
22-
CTxOut txout; // the txout data before being spent
23-
bool fCoinBase; // if the outpoint was the last unspent: whether it belonged to a coinbase
24-
unsigned int nHeight; // if the outpoint was the last unspent: its height
25-
26-
CTxInUndo() : txout(), fCoinBase(false), nHeight(0) {}
27-
CTxInUndo(const CTxOut &txoutIn, bool fCoinBaseIn = false, unsigned int nHeightIn = 0) : txout(txoutIn), fCoinBase(fCoinBaseIn), nHeight(nHeightIn) { }
23+
const Coin* txout;
2824

25+
public:
2926
template<typename Stream>
3027
void Serialize(Stream &s) const {
31-
::Serialize(s, VARINT(nHeight*2+(fCoinBase ? 1 : 0)));
32-
if (nHeight > 0) {
33-
int nVersionDummy = 0;
34-
::Serialize(s, VARINT(nVersionDummy));
28+
::Serialize(s, VARINT(txout->nHeight * 2 + (txout->fCoinBase ? 1 : 0)));
29+
if (txout->nHeight > 0) {
30+
// Required to maintain compatibility with older undo format.
31+
::Serialize(s, (unsigned char)0);
3532
}
36-
::Serialize(s, CTxOutCompressor(REF(txout)));
33+
::Serialize(s, CTxOutCompressor(REF(txout->out)));
3734
}
3835

36+
TxInUndoSerializer(const Coin* coin) : txout(coin) {}
37+
};
38+
39+
class TxInUndoDeserializer
40+
{
41+
Coin* txout;
42+
43+
public:
3944
template<typename Stream>
4045
void Unserialize(Stream &s) {
4146
unsigned int nCode = 0;
4247
::Unserialize(s, VARINT(nCode));
43-
nHeight = nCode / 2;
44-
fCoinBase = nCode & 1;
45-
if (nHeight > 0) {
48+
txout->nHeight = nCode / 2;
49+
txout->fCoinBase = nCode & 1;
50+
if (txout->nHeight > 0) {
51+
// Old versions stored the version number for the last spend of
52+
// a transaction's outputs. Non-final spends were indicated with
53+
// height = 0.
4654
int nVersionDummy;
4755
::Unserialize(s, VARINT(nVersionDummy));
4856
}
49-
::Unserialize(s, REF(CTxOutCompressor(REF(txout))));
57+
::Unserialize(s, REF(CTxOutCompressor(REF(txout->out))));
5058
}
59+
60+
TxInUndoDeserializer(Coin* coin) : txout(coin) {}
5161
};
5262

63+
static const size_t MAX_INPUTS_PER_BLOCK = MAX_BLOCK_BASE_SIZE / ::GetSerializeSize(CTxIn(), SER_NETWORK, PROTOCOL_VERSION);
64+
5365
/** Undo information for a CTransaction */
5466
class CTxUndo
5567
{
5668
public:
5769
// undo information for all txins
58-
std::vector<CTxInUndo> vprevout;
70+
std::vector<Coin> vprevout;
5971

60-
ADD_SERIALIZE_METHODS;
72+
template <typename Stream>
73+
void Serialize(Stream& s) const {
74+
// TODO: avoid reimplementing vector serializer
75+
uint64_t count = vprevout.size();
76+
::Serialize(s, COMPACTSIZE(REF(count)));
77+
for (const auto& prevout : vprevout) {
78+
::Serialize(s, REF(TxInUndoSerializer(&prevout)));
79+
}
80+
}
6181

62-
template <typename Stream, typename Operation>
63-
inline void SerializationOp(Stream& s, Operation ser_action) {
64-
READWRITE(vprevout);
82+
template <typename Stream>
83+
void Unserialize(Stream& s) {
84+
// TODO: avoid reimplementing vector deserializer
85+
uint64_t count = 0;
86+
::Unserialize(s, COMPACTSIZE(count));
87+
if (count > MAX_INPUTS_PER_BLOCK) {
88+
throw std::ios_base::failure("Too many input undo records");
89+
}
90+
vprevout.resize(count);
91+
for (auto& prevout : vprevout) {
92+
::Unserialize(s, REF(TxInUndoDeserializer(&prevout)));
93+
}
6594
}
6695
};
6796

src/validation.cpp

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,11 +1080,9 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txund
10801080
if (nPos >= coins->vout.size() || coins->vout[nPos].IsNull())
10811081
assert(false);
10821082
// mark an outpoint spent, and construct undo information
1083-
txundo.vprevout.push_back(CTxInUndo(coins->vout[nPos]));
1084-
coins->Spend(nPos);
1085-
CTxInUndo& undo = txundo.vprevout.back();
1086-
undo.nHeight = coins->nHeight;
1087-
undo.fCoinBase = coins->fCoinBase;
1083+
txundo.vprevout.emplace_back(coins->vout[nPos], coins->nHeight, coins->fCoinBase);
1084+
bool ret = coins->Spend(nPos);
1085+
assert(ret);
10881086
}
10891087
}
10901088
// add outputs
@@ -1252,13 +1250,13 @@ enum DisconnectResult
12521250
};
12531251

12541252
/**
1255-
* Apply the undo operation of a CTxInUndo to the given chain state.
1256-
* @param undo The undo object.
1253+
* Restore the UTXO in a Coin at a given COutPoint
1254+
* @param undo The Coin to be restored.
12571255
* @param view The coins view to which to apply the changes.
12581256
* @param out The out point that corresponds to the tx input.
12591257
* @return A DisconnectResult as an int
12601258
*/
1261-
int ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const COutPoint& out)
1259+
int ApplyTxInUndo(const Coin& undo, CCoinsViewCache& view, const COutPoint& out)
12621260
{
12631261
bool fClean = true;
12641262

@@ -1279,7 +1277,7 @@ int ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const COutPoint&
12791277
if (coins->IsAvailable(out.n)) fClean = false; // overwriting existing output
12801278
if (coins->vout.size() < out.n+1)
12811279
coins->vout.resize(out.n+1);
1282-
coins->vout[out.n] = undo.txout;
1280+
coins->vout[out.n] = undo.out;
12831281

12841282
return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN;
12851283
}
@@ -1335,7 +1333,7 @@ static DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex*
13351333
}
13361334
for (unsigned int j = tx.vin.size(); j-- > 0;) {
13371335
const COutPoint &out = tx.vin[j].prevout;
1338-
const CTxInUndo &undo = txundo.vprevout[j];
1336+
const Coin &undo = txundo.vprevout[j];
13391337
int res = ApplyTxInUndo(undo, view, out);
13401338
if (res == DISCONNECT_FAILED) return DISCONNECT_FAILED;
13411339
fClean = fClean && res != DISCONNECT_UNCLEAN;

0 commit comments

Comments
 (0)