Changeset View
Changeset View
Standalone View
Standalone View
src/coins.h
Show First 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | template <typename Stream> void Unserialize(Stream &s) { | ||||
::Unserialize(s, REF(CTxOutCompressor(out))); | ::Unserialize(s, REF(CTxOutCompressor(out))); | ||||
} | } | ||||
size_t DynamicMemoryUsage() const { | size_t DynamicMemoryUsage() const { | ||||
return memusage::DynamicUsage(out.scriptPubKey); | return memusage::DynamicUsage(out.scriptPubKey); | ||||
} | } | ||||
}; | }; | ||||
/** | |||||
* Pruned version of CTransaction: only retains metadata and unspent transaction outputs | |||||
* | |||||
* Serialized format: | |||||
* - VARINT(nVersion) - DEPRECATED, always zero on new reccords. | |||||
* - VARINT(nCode) | |||||
* - unspentness bitvector, for vout[2] and further; least significant byte first | |||||
* - the non-spent CTxOuts (via CTxOutCompressor) | |||||
* - VARINT(nHeight) | |||||
* | |||||
* The nCode value consists of: | |||||
* - bit 0: IsCoinBase() | |||||
* - bit 1: vout[0] is not spent | |||||
* - bit 2: vout[1] is not spent | |||||
* - The higher bits encode N, the number of non-zero bytes in the following bitvector. | |||||
* - In case both bit 1 and bit 2 are unset, they encode N-1, as there must be at | |||||
* least one non-spent output). | |||||
* | |||||
* Example: 0104835800816115944e077fe7c803cfa57f29b36bf87c1d358bb85e | |||||
* <><><--------------------------------------------><----> | |||||
* | \ | / | |||||
* version code vout[1] height | |||||
* | |||||
* - version = 1 | |||||
* - code = 4 (vout[1] is not spent, and 0 non-zero bytes of bitvector follow) | |||||
* - unspentness bitvector: as 0 non-zero bytes follow, it has length 0 | |||||
* - vout[1]: 835800816115944e077fe7c803cfa57f29b36bf87c1d35 | |||||
* * 8358: compact amount representation for 60000000000 (600 BCC) | |||||
* * 00: special txout type pay-to-pubkey-hash | |||||
* * 816115944e077fe7c803cfa57f29b36bf87c1d35: address uint160 | |||||
* - height = 203998 | |||||
* | |||||
* | |||||
* Example: 0109044086ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4eebbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa486af3b | |||||
* <><><--><--------------------------------------------------><----------------------------------------------><----> | |||||
* / \ \ | | / | |||||
* version code unspentness vout[4] vout[16] height | |||||
* | |||||
* - version = 1 | |||||
* - code = 9 (coinbase, neither vout[0] or vout[1] are unspent, | |||||
* 2 (1, +1 because both bit 1 and bit 2 are unset) non-zero bitvector bytes follow) | |||||
* - unspentness bitvector: bits 2 (0x04) and 14 (0x4000) are set, so vout[2+2] and vout[14+2] are unspent | |||||
* - vout[4]: 86ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4ee | |||||
* * 86ef97d579: compact amount representation for 234925952 (2.35 BCC) | |||||
* * 00: special txout type pay-to-pubkey-hash | |||||
* * 61b01caab50f1b8e9c50a5057eb43c2d9563a4ee: address uint160 | |||||
* - vout[16]: bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4 | |||||
* * bbd123: compact amount representation for 110397 (0.001 BCC) | |||||
* * 00: special txout type pay-to-pubkey-hash | |||||
* * 8c988f1a4a4de2161e0f50aac7f17e7f9555caa4: address uint160 | |||||
* - height = 120891 | |||||
* | |||||
* @DISABLE FORMATING FOR THIS COMMENT@ | |||||
*/ | |||||
class CCoins { | |||||
public: | |||||
//! whether transaction is a coinbase | |||||
bool fCoinBase; | |||||
//! unspent transaction outputs; spent outputs are .IsNull(); spent outputs | |||||
//! at the end of the array are dropped | |||||
std::vector<CTxOut> vout; | |||||
//! at which height this transaction was included in the active block chain | |||||
int nHeight; | |||||
void FromTx(const CTransaction &tx, int nHeightIn) { | |||||
fCoinBase = tx.IsCoinBase(); | |||||
vout = tx.vout; | |||||
nHeight = nHeightIn; | |||||
ClearUnspendable(); | |||||
} | |||||
//! construct a CCoins from a CTransaction, at a given height | |||||
CCoins(const CTransaction &tx, int nHeightIn) { FromTx(tx, nHeightIn); } | |||||
void Clear() { | |||||
fCoinBase = false; | |||||
std::vector<CTxOut>().swap(vout); | |||||
nHeight = 0; | |||||
} | |||||
//! empty constructor | |||||
CCoins() : fCoinBase(false), vout(0), nHeight(0) {} | |||||
//! remove spent outputs at the end of vout | |||||
void Cleanup() { | |||||
while (vout.size() > 0 && vout.back().IsNull()) { | |||||
vout.pop_back(); | |||||
} | |||||
if (vout.empty()) { | |||||
std::vector<CTxOut>().swap(vout); | |||||
} | |||||
} | |||||
void ClearUnspendable() { | |||||
for (CTxOut &txout : vout) { | |||||
if (txout.scriptPubKey.IsUnspendable()) { | |||||
txout.SetNull(); | |||||
} | |||||
} | |||||
Cleanup(); | |||||
} | |||||
void swap(CCoins &to) { | |||||
std::swap(to.fCoinBase, fCoinBase); | |||||
to.vout.swap(vout); | |||||
std::swap(to.nHeight, nHeight); | |||||
} | |||||
//! equality test | |||||
friend bool operator==(const CCoins &a, const CCoins &b) { | |||||
// Empty CCoins objects are always equal. | |||||
if (a.IsPruned() && b.IsPruned()) { | |||||
return true; | |||||
} | |||||
return a.fCoinBase == b.fCoinBase && a.nHeight == b.nHeight && | |||||
a.vout == b.vout; | |||||
} | |||||
friend bool operator!=(const CCoins &a, const CCoins &b) { | |||||
return !(a == b); | |||||
} | |||||
void CalcMaskSize(unsigned int &nBytes, unsigned int &nNonzeroBytes) const; | |||||
bool IsCoinBase() const { return fCoinBase; } | |||||
template <typename Stream> void Serialize(Stream &s) const { | |||||
unsigned int nMaskSize = 0, nMaskCode = 0; | |||||
CalcMaskSize(nMaskSize, nMaskCode); | |||||
bool fFirst = vout.size() > 0 && !vout[0].IsNull(); | |||||
bool fSecond = vout.size() > 1 && !vout[1].IsNull(); | |||||
assert(fFirst || fSecond || nMaskCode); | |||||
unsigned int nCode = 8 * (nMaskCode - (fFirst || fSecond ? 0 : 1)) + | |||||
(fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + | |||||
(fSecond ? 4 : 0); | |||||
// version | |||||
int nVersionDummy = 0; | |||||
::Serialize(s, VARINT(nVersionDummy)); | |||||
// header code | |||||
::Serialize(s, VARINT(nCode)); | |||||
// spentness bitmask | |||||
for (unsigned int b = 0; b < nMaskSize; b++) { | |||||
uint8_t chAvail = 0; | |||||
for (size_t i = 0; i < 8 && 2 + b * 8 + i < vout.size(); i++) { | |||||
if (!vout[2 + b * 8 + i].IsNull()) { | |||||
chAvail |= (1 << i); | |||||
} | |||||
} | |||||
::Serialize(s, chAvail); | |||||
} | |||||
// txouts themself | |||||
for (unsigned int i = 0; i < vout.size(); i++) { | |||||
if (!vout[i].IsNull()) { | |||||
::Serialize(s, CTxOutCompressor(REF(vout[i]))); | |||||
} | |||||
} | |||||
// coinbase height | |||||
::Serialize(s, VARINT(nHeight)); | |||||
} | |||||
template <typename Stream> void Unserialize(Stream &s) { | |||||
unsigned int nCode = 0; | |||||
// version | |||||
int nVersionDummy; | |||||
::Unserialize(s, VARINT(nVersionDummy)); | |||||
// header code | |||||
::Unserialize(s, VARINT(nCode)); | |||||
fCoinBase = nCode & 1; | |||||
std::vector<bool> vAvail(2, false); | |||||
vAvail[0] = (nCode & 2) != 0; | |||||
vAvail[1] = (nCode & 4) != 0; | |||||
unsigned int nMaskCode = (nCode / 8) + ((nCode & 6) != 0 ? 0 : 1); | |||||
// spentness bitmask | |||||
while (nMaskCode > 0) { | |||||
uint8_t chAvail = 0; | |||||
::Unserialize(s, chAvail); | |||||
for (unsigned int p = 0; p < 8; p++) { | |||||
bool f = (chAvail & (1 << p)) != 0; | |||||
vAvail.push_back(f); | |||||
} | |||||
if (chAvail != 0) { | |||||
nMaskCode--; | |||||
} | |||||
} | |||||
// txouts themself | |||||
vout.assign(vAvail.size(), CTxOut()); | |||||
for (unsigned int i = 0; i < vAvail.size(); i++) { | |||||
if (vAvail[i]) { | |||||
::Unserialize(s, REF(CTxOutCompressor(vout[i]))); | |||||
} | |||||
} | |||||
// coinbase height | |||||
::Unserialize(s, VARINT(nHeight)); | |||||
Cleanup(); | |||||
} | |||||
//! mark a vout spent | |||||
bool Spend(uint32_t nPos); | |||||
//! check whether a particular output is still available | |||||
bool IsAvailable(unsigned int nPos) const { | |||||
return (nPos < vout.size() && !vout[nPos].IsNull()); | |||||
} | |||||
//! check whether the entire CCoins is spent | |||||
//! note that only !IsPruned() CCoins can be serialized | |||||
bool IsPruned() const { | |||||
for (const CTxOut &out : vout) { | |||||
if (!out.IsNull()) { | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
size_t DynamicMemoryUsage() const { | |||||
size_t ret = memusage::DynamicUsage(vout); | |||||
for (const CTxOut &out : vout) { | |||||
ret += RecursiveDynamicUsage(out.scriptPubKey); | |||||
} | |||||
return ret; | |||||
} | |||||
}; | |||||
class SaltedOutpointHasher { | class SaltedOutpointHasher { | ||||
private: | private: | ||||
/** Salt */ | /** Salt */ | ||||
const uint64_t k0, k1; | const uint64_t k0, k1; | ||||
public: | public: | ||||
SaltedOutpointHasher(); | SaltedOutpointHasher(); | ||||
▲ Show 20 Lines • Show All 218 Lines • Show Last 20 Lines |