changeset 3644:e62eeca19443 draft

Add CTxUndo: transaction undo information The CTxUndo class encapsulates data necessary to undo the effects of a transaction on the txout set, namely the previous outputs consumed by it (script + amount), and potentially transaction meta-data when it is spent entirely.
author Pieter Wuille <pieter.wuille@gmail.com>
date Mon, 18 Jun 2012 16:55:29 +0200
parents f892cfa05d62
children 1f8d48b2b3c5
files src/main.h
diffstat 1 files changed, 64 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/main.h
+++ b/src/main.h
@@ -673,6 +673,60 @@
     });)
 };
 
+/** Undo information for a CTxIn
+ *
+ *  Contains the prevout's CTxOut being spent, and if this was the
+ *  last output of the affected transaction, its metadata as well
+ *  (coinbase or not, height, transaction version)
+ */
+class CTxInUndo
+{
+public:
+    CTxOut txout;         // the txout data before being spent
+    bool fCoinBase;       // if the outpoint was the last unspent: whether it belonged to a coinbase
+    unsigned int nHeight; // if the outpoint was the last unspent: its height
+    int nVersion;         // if the outpoint was the last unspent: its version
+
+    CTxInUndo() : txout(), fCoinBase(false), nHeight(0), nVersion(0) {}
+    CTxInUndo(const CTxOut &txoutIn, bool fCoinBaseIn = false, unsigned int nHeightIn = 0, int nVersionIn = 0) : txout(txoutIn), fCoinBase(fCoinBaseIn), nHeight(nHeightIn), nVersion(nVersionIn) { }
+
+    unsigned int GetSerializeSize(int nType, int nVersion) const {
+        return ::GetSerializeSize(VARINT(nHeight*2+(fCoinBase ? 1 : 0)), nType, nVersion) +
+               (nHeight > 0 ? ::GetSerializeSize(VARINT(this->nVersion), nType, nVersion) : 0) +
+               ::GetSerializeSize(CTxOutCompressor(REF(txout)), nType, nVersion);
+    }
+
+    template<typename Stream>
+    void Serialize(Stream &s, int nType, int nVersion) const {
+        ::Serialize(s, VARINT(nHeight*2+(fCoinBase ? 1 : 0)), nType, nVersion);
+        if (nHeight > 0)
+            ::Serialize(s, VARINT(this->nVersion), nType, nVersion);
+        ::Serialize(s, CTxOutCompressor(REF(txout)), nType, nVersion);
+    }
+
+    template<typename Stream>
+    void Unserialize(Stream &s, int nType, int nVersion) {
+        unsigned int nCode = 0;
+        ::Unserialize(s, VARINT(nCode), nType, nVersion);
+        nHeight = nCode / 2;
+        fCoinBase = nCode & 1;
+        if (nHeight > 0)
+            ::Unserialize(s, VARINT(this->nVersion), nType, nVersion);
+        ::Unserialize(s, REF(CTxOutCompressor(REF(txout))), nType, nVersion);
+    }
+};
+
+/** Undo information for a CTransaction */
+class CTxUndo
+{
+public:
+    std::vector<CTxInUndo> vprevout;
+
+    IMPLEMENT_SERIALIZE(
+        READWRITE(vprevout);
+    )
+};
+
 /** pruned version of CTransaction: only retains metadata and unspent transaction outputs
  *
  * Serialized format:
@@ -874,21 +928,28 @@
         Cleanup();
     }
 
-    // mark an outpoint spent
-    bool Spend(const COutPoint &out) {
+    // mark an outpoint spent, and construct undo information
+    bool Spend(const COutPoint &out, CTxInUndo &undo) {
         if (out.n >= vout.size())
             return false;
         if (vout[out.n].IsNull())
             return false;
+        undo = CTxInUndo(vout[out.n]);
         vout[out.n].SetNull();
         Cleanup();
+        if (vout.size() == 0) {
+            undo.nHeight = nHeight;
+            undo.fCoinBase = fCoinBase;
+            undo.nVersion = this->nVersion;
+        }
         return true;
     }
 
     // mark a vout spent
     bool Spend(int nPos) {
+        CTxInUndo undo;
         COutPoint out(0, nPos);
-        return Spend(out);
+        return Spend(out, undo);
     }
 
     // check whether a particular output is still available