Changeset View
Changeset View
Standalone View
Standalone View
src/undo.h
Show All 14 Lines | |||||
#include <version.h> | #include <version.h> | ||||
class CBlock; | class CBlock; | ||||
class CBlockIndex; | class CBlockIndex; | ||||
class CCoinsViewCache; | class CCoinsViewCache; | ||||
class BlockValidationState; | class BlockValidationState; | ||||
/** | /** | ||||
* Undo information for a CTxIn | * Formatter for undo information for a CTxIn | ||||
* | * | ||||
* Contains the prevout's CTxOut being spent, and its metadata as well (coinbase | * Contains the prevout's CTxOut being spent, and its metadata as well (coinbase | ||||
* or not, height). The serialization contains a dummy value of zero. This is | * or not, height). The serialization contains a dummy value of zero. This is | ||||
* compatible with older versions which expect to see the transaction version | * compatible with older versions which expect to see the transaction version | ||||
* there. | * there. | ||||
*/ | */ | ||||
class TxInUndoSerializer { | struct TxInUndoFormatter { | ||||
const Coin *pcoin; | template <typename Stream> void Ser(Stream &s, const Coin &txout) { | ||||
public: | |||||
explicit TxInUndoSerializer(const Coin *pcoinIn) : pcoin(pcoinIn) {} | |||||
template <typename Stream> void Serialize(Stream &s) const { | |||||
::Serialize( | ::Serialize( | ||||
s, VARINT(pcoin->GetHeight() * 2 + (pcoin->IsCoinBase() ? 1 : 0))); | s, VARINT(txout.GetHeight() * 2 + (txout.IsCoinBase() ? 1 : 0))); | ||||
if (pcoin->GetHeight() > 0) { | if (txout.GetHeight() > 0) { | ||||
// Required to maintain compatibility with older undo format. | // Required to maintain compatibility with older undo format. | ||||
::Serialize(s, uint8_t(0)); | ::Serialize(s, uint8_t(0)); | ||||
} | } | ||||
::Serialize(s, Using<TxOutCompression>(REF(pcoin->GetTxOut()))); | ::Serialize(s, Using<TxOutCompression>(txout.GetTxOut())); | ||||
} | } | ||||
}; | |||||
class TxInUndoDeserializer { | template <typename Stream> void Unser(Stream &s, Coin &txout) { | ||||
Coin *pcoin; | |||||
public: | |||||
explicit TxInUndoDeserializer(Coin *pcoinIn) : pcoin(pcoinIn) {} | |||||
template <typename Stream> void Unserialize(Stream &s) { | |||||
uint32_t nCode = 0; | uint32_t nCode = 0; | ||||
::Unserialize(s, VARINT(nCode)); | ::Unserialize(s, VARINT(nCode)); | ||||
uint32_t nHeight = nCode / 2; | uint32_t nHeight = nCode / 2; | ||||
bool fCoinBase = nCode & 1; | bool fCoinBase = nCode & 1; | ||||
if (nHeight > 0) { | if (nHeight > 0) { | ||||
// Old versions stored the version number for the last spend of a | // Old versions stored the version number for the last spend of a | ||||
// transaction's outputs. Non-final spends were indicated with | // transaction's outputs. Non-final spends were indicated with | ||||
// height = 0. | // height = 0. | ||||
unsigned int nVersionDummy = 0; | unsigned int nVersionDummy = 0; | ||||
::Unserialize(s, VARINT(nVersionDummy)); | ::Unserialize(s, VARINT(nVersionDummy)); | ||||
} | } | ||||
CTxOut txout; | CTxOut out; | ||||
::Unserialize(s, Using<TxOutCompression>(REF(txout))); | ::Unserialize(s, Using<TxOutCompression>(out)); | ||||
*pcoin = Coin(std::move(txout), nHeight, fCoinBase); | txout = Coin(std::move(out), nHeight, fCoinBase); | ||||
} | } | ||||
}; | }; | ||||
static const size_t MAX_INPUTS_PER_TX = | |||||
MAX_TX_SIZE / ::GetSerializeSize(CTxIn(), PROTOCOL_VERSION); | |||||
/** Restore the UTXO in a Coin at a given COutPoint */ | /** Restore the UTXO in a Coin at a given COutPoint */ | ||||
class CTxUndo { | class CTxUndo { | ||||
public: | public: | ||||
// Undo information for all txins | // Undo information for all txins | ||||
std::vector<Coin> vprevout; | std::vector<Coin> vprevout; | ||||
template <typename Stream> void Serialize(Stream &s) const { | SERIALIZE_METHODS(CTxUndo, obj) { | ||||
// TODO: avoid reimplementing vector serializer. | READWRITE(Using<VectorFormatter<TxInUndoFormatter>>(obj.vprevout)); | ||||
uint64_t count = vprevout.size(); | |||||
::Serialize(s, COMPACTSIZE(REF(count))); | |||||
for (const auto &prevout : vprevout) { | |||||
::Serialize(s, TxInUndoSerializer(&prevout)); | |||||
} | |||||
} | |||||
template <typename Stream> void Unserialize(Stream &s) { | |||||
// TODO: avoid reimplementing vector deserializer. | |||||
uint64_t count = 0; | |||||
::Unserialize(s, COMPACTSIZE(count)); | |||||
if (count > MAX_INPUTS_PER_TX) { | |||||
throw std::ios_base::failure("Too many input undo records"); | |||||
} | |||||
vprevout.resize(count); | |||||
for (auto &prevout : vprevout) { | |||||
::Unserialize(s, TxInUndoDeserializer(&prevout)); | |||||
} | |||||
} | } | ||||
}; | }; | ||||
/** Undo information for a CBlock */ | /** Undo information for a CBlock */ | ||||
class CBlockUndo { | class CBlockUndo { | ||||
public: | public: | ||||
// For all but the coinbase | // For all but the coinbase | ||||
std::vector<CTxUndo> vtxundo; | std::vector<CTxUndo> vtxundo; | ||||
ADD_SERIALIZE_METHODS; | SERIALIZE_METHODS(CBlockUndo, obj) { READWRITE(obj.vtxundo); } | ||||
template <typename Stream, typename Operation> | |||||
inline void SerializationOp(Stream &s, Operation ser_action) { | |||||
READWRITE(vtxundo); | |||||
} | |||||
}; | }; | ||||
/** | /** | ||||
* Restore the UTXO in a Coin at a given COutPoint. | * Restore the UTXO in a Coin at a given COutPoint. | ||||
* @param undo The Coin to be restored. | * @param undo The Coin to be restored. | ||||
* @param view The coins view to which to apply the changes. | * @param view The coins view to which to apply the changes. | ||||
* @param out The out point that corresponds to the tx input. | * @param out The out point that corresponds to the tx input. | ||||
* @return A DisconnectResult | * @return A DisconnectResult | ||||
Show All 13 Lines |