Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.h
Show First 20 Lines • Show All 396 Lines • ▼ Show 20 Lines | |||||
* A transaction with a bunch of additional info that only the owner cares | * A transaction with a bunch of additional info that only the owner cares | ||||
* about. It includes any unrecorded transactions needed to link it back to the | * about. It includes any unrecorded transactions needed to link it back to the | ||||
* block chain. | * block chain. | ||||
*/ | */ | ||||
class CWalletTx { | class CWalletTx { | ||||
private: | private: | ||||
const CWallet *pwallet; | const CWallet *pwallet; | ||||
/** Constant used in hashBlock to indicate tx has been abandoned */ | /** | ||||
* Constant used in hashBlock to indicate tx has been abandoned, only used | |||||
* at serialization/deserialization to avoid ambiguity with conflicted. | |||||
*/ | |||||
static const BlockHash ABANDON_HASH; | static const BlockHash ABANDON_HASH; | ||||
public: | public: | ||||
/** | /** | ||||
* Key/value map with information about the transaction. | * Key/value map with information about the transaction. | ||||
* | * | ||||
* The following keys can be read and written through the map and are | * The following keys can be read and written through the map and are | ||||
* serialized in the wallet database: | * serialized in the wallet database: | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | public: | ||||
Amount GetCachableAmount(AmountType type, const isminefilter &filter, | Amount GetCachableAmount(AmountType type, const isminefilter &filter, | ||||
bool recalculate = false) const; | bool recalculate = false) const; | ||||
mutable CachableAmount m_amounts[AMOUNTTYPE_ENUM_ELEMENTS]; | mutable CachableAmount m_amounts[AMOUNTTYPE_ENUM_ELEMENTS]; | ||||
mutable bool fChangeCached; | mutable bool fChangeCached; | ||||
mutable bool fInMempool; | mutable bool fInMempool; | ||||
mutable Amount nChangeCached; | mutable Amount nChangeCached; | ||||
CWalletTx(const CWallet *pwalletIn, CTransactionRef arg) | CWalletTx(const CWallet *pwalletIn, CTransactionRef arg) | ||||
: tx(std::move(arg)), hashBlock(BlockHash()), nIndex(-1) { | : tx(std::move(arg)) { | ||||
Init(pwalletIn); | Init(pwalletIn); | ||||
} | } | ||||
void Init(const CWallet *pwalletIn) { | void Init(const CWallet *pwalletIn) { | ||||
pwallet = pwalletIn; | pwallet = pwalletIn; | ||||
mapValue.clear(); | mapValue.clear(); | ||||
vOrderForm.clear(); | vOrderForm.clear(); | ||||
fTimeReceivedIsTxTime = false; | fTimeReceivedIsTxTime = false; | ||||
nTimeReceived = 0; | nTimeReceived = 0; | ||||
nTimeSmart = 0; | nTimeSmart = 0; | ||||
fFromMe = false; | fFromMe = false; | ||||
fChangeCached = false; | fChangeCached = false; | ||||
fInMempool = false; | fInMempool = false; | ||||
nChangeCached = Amount::zero(); | nChangeCached = Amount::zero(); | ||||
nOrderPos = -1; | nOrderPos = -1; | ||||
m_confirm = Confirmation{}; | |||||
} | } | ||||
CTransactionRef tx; | CTransactionRef tx; | ||||
BlockHash hashBlock; | |||||
/** | /** | ||||
* An nIndex == -1 means that hashBlock (in nonzero) refers to the earliest | * New transactions start as UNCONFIRMED. At BlockConnected, | ||||
* block in the chain we know this or any in-wallet dependency conflicts | * they will transition to CONFIRMED. In case of reorg, at | ||||
* with. Older clients interpret nIndex == -1 as unconfirmed for backward | * BlockDisconnected, they roll back to UNCONFIRMED. If we detect a | ||||
* compatibility. | * conflicting transaction at block connection, we update conflicted tx and | ||||
*/ | * its dependencies as CONFLICTED. If tx isn't confirmed and outside of | ||||
int nIndex; | * mempool, the user may switch it to ABANDONED by using the | ||||
* abandontransaction call. This last status may be override by a CONFLICTED | |||||
* or CONFIRMED transition. | |||||
*/ | |||||
enum Status { UNCONFIRMED, CONFIRMED, CONFLICTED, ABANDONED }; | |||||
/** | |||||
* Confirmation includes tx status and a pair of {block hash/tx index in | |||||
* block} at which tx has been confirmed. This pair is both 0 if tx hasn't | |||||
* confirmed yet. Meaning of these fields changes with CONFLICTED state | |||||
* where they instead point to block hash and index of the deepest | |||||
* conflicting tx. | |||||
*/ | |||||
struct Confirmation { | |||||
Status status = UNCONFIRMED; | |||||
BlockHash hashBlock = BlockHash(); | |||||
int nIndex = 0; | |||||
}; | |||||
Confirmation m_confirm; | |||||
template <typename Stream> void Serialize(Stream &s) const { | template <typename Stream> void Serialize(Stream &s) const { | ||||
mapValue_t mapValueCopy = mapValue; | mapValue_t mapValueCopy = mapValue; | ||||
mapValueCopy["fromaccount"] = ""; | mapValueCopy["fromaccount"] = ""; | ||||
WriteOrderPos(nOrderPos, mapValueCopy); | WriteOrderPos(nOrderPos, mapValueCopy); | ||||
if (nTimeSmart) { | if (nTimeSmart) { | ||||
mapValueCopy["timesmart"] = strprintf("%u", nTimeSmart); | mapValueCopy["timesmart"] = strprintf("%u", nTimeSmart); | ||||
} | } | ||||
//! Used to be vMerkleBranch | //! Used to be vMerkleBranch | ||||
std::vector<char> dummy_vector1; | std::vector<char> dummy_vector1; | ||||
//! Used to be vtxPrev | //! Used to be vtxPrev | ||||
std::vector<char> dummy_vector2; | std::vector<char> dummy_vector2; | ||||
//! Used to be fSpent | //! Used to be fSpent | ||||
bool dummy_bool = false; | bool dummy_bool = false; | ||||
s << tx << hashBlock << dummy_vector1 << nIndex << dummy_vector2 | uint256 serializedHash = | ||||
<< mapValueCopy << vOrderForm << fTimeReceivedIsTxTime | isAbandoned() ? ABANDON_HASH : m_confirm.hashBlock; | ||||
<< nTimeReceived << fFromMe << dummy_bool; | int serializedIndex = | ||||
isAbandoned() || isConflicted() ? -1 : m_confirm.nIndex; | |||||
s << tx << serializedHash << dummy_vector1 << serializedIndex | |||||
<< dummy_vector2 << mapValueCopy << vOrderForm | |||||
<< fTimeReceivedIsTxTime << nTimeReceived << fFromMe << dummy_bool; | |||||
} | } | ||||
template <typename Stream> void Unserialize(Stream &s) { | template <typename Stream> void Unserialize(Stream &s) { | ||||
Init(nullptr); | Init(nullptr); | ||||
//! Used to be vMerkleBranch | //! Used to be vMerkleBranch | ||||
std::vector<uint256> dummy_vector1; | std::vector<uint256> dummy_vector1; | ||||
//! Used to be vtxPrev | //! Used to be vtxPrev | ||||
std::vector<CMerkleTx> dummy_vector2; | std::vector<CMerkleTx> dummy_vector2; | ||||
//! Used to be fSpent | //! Used to be fSpent | ||||
bool dummy_bool; | bool dummy_bool; | ||||
s >> tx >> hashBlock >> dummy_vector1 >> nIndex >> dummy_vector2 >> | int serializedIndex; | ||||
mapValue >> vOrderForm >> fTimeReceivedIsTxTime >> nTimeReceived >> | s >> tx >> m_confirm.hashBlock >> dummy_vector1 >> serializedIndex >> | ||||
fFromMe >> dummy_bool; | dummy_vector2 >> mapValue >> vOrderForm >> fTimeReceivedIsTxTime >> | ||||
nTimeReceived >> fFromMe >> dummy_bool; | |||||
/* | |||||
* At serialization/deserialization, an nIndex == -1 means that | |||||
* hashBlock refers to the earliest block in the chain we know this or | |||||
* any in-wallet ancestor conflicts with. If nIndex == -1 and hashBlock | |||||
* is ABANDON_HASH, it means transaction is abandoned. In same context, | |||||
* an nIndex >= 0 refers to a confirmed transaction (if hashBlock set) | |||||
* or unconfirmed one. Older clients interpret nIndex == -1 as | |||||
* unconfirmed for backward compatibility (pre-commit 9ac63d6). | |||||
*/ | |||||
if (serializedIndex == -1 && m_confirm.hashBlock == ABANDON_HASH) { | |||||
m_confirm.hashBlock = BlockHash(); | |||||
setAbandoned(); | |||||
} else if (serializedIndex == -1) { | |||||
setConflicted(); | |||||
} else if (!m_confirm.hashBlock.IsNull()) { | |||||
m_confirm.nIndex = serializedIndex; | |||||
setConfirmed(); | |||||
} | |||||
ReadOrderPos(nOrderPos, mapValue); | ReadOrderPos(nOrderPos, mapValue); | ||||
nTimeSmart = mapValue.count("timesmart") | nTimeSmart = mapValue.count("timesmart") | ||||
? (unsigned int)atoi64(mapValue["timesmart"]) | ? (unsigned int)atoi64(mapValue["timesmart"]) | ||||
: 0; | : 0; | ||||
mapValue.erase("fromaccount"); | mapValue.erase("fromaccount"); | ||||
mapValue.erase("spent"); | mapValue.erase("spent"); | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | public: | ||||
// TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct | // TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct | ||||
// annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The annotation | // annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The annotation | ||||
// "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid having to | // "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid having to | ||||
// resolve the issue of member access into incomplete type CWallet. Note | // resolve the issue of member access into incomplete type CWallet. Note | ||||
// that we still have the runtime check "AssertLockHeld(pwallet->cs_wallet)" | // that we still have the runtime check "AssertLockHeld(pwallet->cs_wallet)" | ||||
// in place. | // in place. | ||||
std::set<TxId> GetConflicts() const NO_THREAD_SAFETY_ANALYSIS; | std::set<TxId> GetConflicts() const NO_THREAD_SAFETY_ANALYSIS; | ||||
void SetMerkleBranch(const BlockHash &block_hash, int posInBlock); | void SetConf(Status status, const BlockHash &block_hash, int posInBlock); | ||||
/** | /** | ||||
* Return depth of transaction in blockchain: | * Return depth of transaction in blockchain: | ||||
* <0 : conflicts with a transaction this deep in the blockchain | * <0 : conflicts with a transaction this deep in the blockchain | ||||
* 0 : in memory pool, waiting to be included in a block | * 0 : in memory pool, waiting to be included in a block | ||||
* >=1 : this many blocks deep in the main chain | * >=1 : this many blocks deep in the main chain | ||||
*/ | */ | ||||
int GetDepthInMainChain(interfaces::Chain::Lock &locked_chain) const; | int GetDepthInMainChain(interfaces::Chain::Lock &locked_chain) const; | ||||
bool IsInMainChain(interfaces::Chain::Lock &locked_chain) const { | bool IsInMainChain(interfaces::Chain::Lock &locked_chain) const { | ||||
return GetDepthInMainChain(locked_chain) > 0; | return GetDepthInMainChain(locked_chain) > 0; | ||||
} | } | ||||
/** | /** | ||||
* @return number of blocks to maturity for this transaction: | * @return number of blocks to maturity for this transaction: | ||||
* 0 : is not a coinbase transaction, or is a mature coinbase transaction | * 0 : is not a coinbase transaction, or is a mature coinbase transaction | ||||
* >0 : is a coinbase transaction which matures in this many blocks | * >0 : is a coinbase transaction which matures in this many blocks | ||||
*/ | */ | ||||
int GetBlocksToMaturity(interfaces::Chain::Lock &locked_chain) const; | int GetBlocksToMaturity(interfaces::Chain::Lock &locked_chain) const; | ||||
bool hashUnset() const { | bool isAbandoned() const { | ||||
return (hashBlock.IsNull() || hashBlock == ABANDON_HASH); | return m_confirm.status == CWalletTx::ABANDONED; | ||||
} | } | ||||
bool isAbandoned() const { return (hashBlock == ABANDON_HASH); } | void setAbandoned() { | ||||
void setAbandoned() { hashBlock = ABANDON_HASH; } | m_confirm.status = CWalletTx::ABANDONED; | ||||
m_confirm.hashBlock = BlockHash(); | |||||
m_confirm.nIndex = 0; | |||||
} | |||||
bool isConflicted() const { | |||||
return m_confirm.status == CWalletTx::CONFLICTED; | |||||
} | |||||
void setConflicted() { m_confirm.status = CWalletTx::CONFLICTED; } | |||||
bool isUnconfirmed() const { | |||||
return m_confirm.status == CWalletTx::UNCONFIRMED; | |||||
} | |||||
void setUnconfirmed() { m_confirm.status = CWalletTx::UNCONFIRMED; } | |||||
void setConfirmed() { m_confirm.status = CWalletTx::CONFIRMED; } | |||||
TxId GetId() const { return tx->GetId(); } | TxId GetId() const { return tx->GetId(); } | ||||
bool IsCoinBase() const { return tx->IsCoinBase(); } | bool IsCoinBase() const { return tx->IsCoinBase(); } | ||||
bool IsImmatureCoinBase(interfaces::Chain::Lock &locked_chain) const; | bool IsImmatureCoinBase(interfaces::Chain::Lock &locked_chain) const; | ||||
}; | }; | ||||
class COutput { | class COutput { | ||||
public: | public: | ||||
const CWalletTx *tx; | const CWalletTx *tx; | ||||
▲ Show 20 Lines • Show All 152 Lines • ▼ Show 20 Lines | private: | ||||
* TODO: One exception to this is that the abandoned state is cleared under | * TODO: One exception to this is that the abandoned state is cleared under | ||||
* the assumption that any further notification of a transaction that was | * the assumption that any further notification of a transaction that was | ||||
* considered abandoned is an indication that it is not safe to be | * considered abandoned is an indication that it is not safe to be | ||||
* considered abandoned. Abandoned state should probably be more carefully | * considered abandoned. Abandoned state should probably be more carefully | ||||
* tracked via different posInBlock signals or by checking mempool presence | * tracked via different posInBlock signals or by checking mempool presence | ||||
* when necessary. | * when necessary. | ||||
*/ | */ | ||||
bool AddToWalletIfInvolvingMe(const CTransactionRef &tx, | bool AddToWalletIfInvolvingMe(const CTransactionRef &tx, | ||||
CWalletTx::Status status, | |||||
const BlockHash &block_hash, int posInBlock, | const BlockHash &block_hash, int posInBlock, | ||||
bool fUpdate) | bool fUpdate) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); | EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); | ||||
/** | /** | ||||
* Mark a transaction (and its in-wallet descendants) as conflicting with a | * Mark a transaction (and its in-wallet descendants) as conflicting with a | ||||
* particular block. | * particular block. | ||||
*/ | */ | ||||
Show All 10 Lines | void SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator>) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); | EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); | ||||
/** | /** | ||||
* Used by | * Used by | ||||
* TransactionAddedToMemorypool/BlockConnected/Disconnected/ScanForWalletTransactions. | * TransactionAddedToMemorypool/BlockConnected/Disconnected/ScanForWalletTransactions. | ||||
* Should be called with non-zero block_hash and posInBlock if this is for a | * Should be called with non-zero block_hash and posInBlock if this is for a | ||||
* transaction that is included in a block. | * transaction that is included in a block. | ||||
*/ | */ | ||||
void SyncTransaction(const CTransactionRef &tx, const BlockHash &block_hash, | void SyncTransaction(const CTransactionRef &tx, CWalletTx::Status status, | ||||
int posInBlock = 0, bool update_tx = true) | const BlockHash &block_hash, int posInBlock = 0, | ||||
bool update_tx = true) | |||||
EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); | EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); | ||||
/* the HD chain data model (external chain counters) */ | /* the HD chain data model (external chain counters) */ | ||||
CHDChain hdChain; | CHDChain hdChain; | ||||
/* HD derive new child key (on internal or external chain) */ | /* HD derive new child key (on internal or external chain) */ | ||||
void DeriveNewChildKey(WalletBatch &batch, CKeyMetadata &metadata, | void DeriveNewChildKey(WalletBatch &batch, CKeyMetadata &metadata, | ||||
CKey &secret, bool internal = false) | CKey &secret, bool internal = false) | ||||
▲ Show 20 Lines • Show All 836 Lines • Show Last 20 Lines |