Initial Vexta Core v0.1.0 release
This commit is contained in:
commit
25c454329d
2481 changed files with 689289 additions and 0 deletions
358
src/wallet/transaction.h
Normal file
358
src/wallet/transaction.h
Normal file
|
|
@ -0,0 +1,358 @@
|
|||
// Copyright (c) 2021 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_WALLET_TRANSACTION_H
|
||||
#define DIGIBYTE_WALLET_TRANSACTION_H
|
||||
|
||||
#include <amount.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <serialize.h>
|
||||
#include <wallet/ismine.h>
|
||||
#include <threadsafety.h>
|
||||
#include <tinyformat.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <util/string.h>
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
struct COutputEntry;
|
||||
|
||||
typedef std::map<std::string, std::string> mapValue_t;
|
||||
|
||||
//Get the marginal bytes of spending the specified output
|
||||
int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* pwallet, bool use_max_sig = false);
|
||||
|
||||
static inline void ReadOrderPos(int64_t& nOrderPos, mapValue_t& mapValue)
|
||||
{
|
||||
if (!mapValue.count("n"))
|
||||
{
|
||||
nOrderPos = -1; // TODO: calculate elsewhere
|
||||
return;
|
||||
}
|
||||
nOrderPos = atoi64(mapValue["n"]);
|
||||
}
|
||||
|
||||
static inline void WriteOrderPos(const int64_t& nOrderPos, mapValue_t& mapValue)
|
||||
{
|
||||
if (nOrderPos == -1)
|
||||
return;
|
||||
mapValue["n"] = ToString(nOrderPos);
|
||||
}
|
||||
|
||||
/** Legacy class used for deserializing vtxPrev for backwards compatibility.
|
||||
* vtxPrev was removed in commit 93a18a3650292afbb441a47d1fa1b94aeb0164e3,
|
||||
* but old wallet.dat files may still contain vtxPrev vectors of CMerkleTxs.
|
||||
* These need to get deserialized for field alignment when deserializing
|
||||
* a CWalletTx, but the deserialized values are discarded.**/
|
||||
class CMerkleTx
|
||||
{
|
||||
public:
|
||||
template<typename Stream>
|
||||
void Unserialize(Stream& s)
|
||||
{
|
||||
CTransactionRef tx;
|
||||
uint256 hashBlock;
|
||||
std::vector<uint256> vMerkleBranch;
|
||||
int nIndex;
|
||||
|
||||
s >> tx >> hashBlock >> vMerkleBranch >> nIndex;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 block chain.
|
||||
*/
|
||||
class CWalletTx
|
||||
{
|
||||
private:
|
||||
const CWallet* const pwallet;
|
||||
|
||||
/** Constant used in hashBlock to indicate tx has been abandoned, only used at
|
||||
* serialization/deserialization to avoid ambiguity with conflicted.
|
||||
*/
|
||||
static constexpr const uint256& ABANDON_HASH = uint256::ONE;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Key/value map with information about the transaction.
|
||||
*
|
||||
* The following keys can be read and written through the map and are
|
||||
* serialized in the wallet database:
|
||||
*
|
||||
* "comment", "to" - comment strings provided to sendtoaddress,
|
||||
* and sendmany wallet RPCs
|
||||
* "replaces_txid" - txid (as HexStr) of transaction replaced by
|
||||
* bumpfee on transaction created by bumpfee
|
||||
* "replaced_by_txid" - txid (as HexStr) of transaction created by
|
||||
* bumpfee on transaction replaced by bumpfee
|
||||
* "from", "message" - obsolete fields that could be set in UI prior to
|
||||
* 2011 (removed in commit 4d9b223)
|
||||
*
|
||||
* The following keys are serialized in the wallet database, but shouldn't
|
||||
* be read or written through the map (they will be temporarily added and
|
||||
* removed from the map during serialization):
|
||||
*
|
||||
* "fromaccount" - serialized strFromAccount value
|
||||
* "n" - serialized nOrderPos value
|
||||
* "timesmart" - serialized nTimeSmart value
|
||||
* "spent" - serialized vfSpent value that existed prior to
|
||||
* 2014 (removed in commit 93a18a3)
|
||||
*/
|
||||
mapValue_t mapValue;
|
||||
std::vector<std::pair<std::string, std::string> > vOrderForm;
|
||||
unsigned int fTimeReceivedIsTxTime;
|
||||
unsigned int nTimeReceived; //!< time received by this node
|
||||
/**
|
||||
* Stable timestamp that never changes, and reflects the order a transaction
|
||||
* was added to the wallet. Timestamp is based on the block time for a
|
||||
* transaction added as part of a block, or else the time when the
|
||||
* transaction was received if it wasn't part of a block, with the timestamp
|
||||
* adjusted in both cases so timestamp order matches the order transactions
|
||||
* were added to the wallet. More details can be found in
|
||||
* CWallet::ComputeTimeSmart().
|
||||
*/
|
||||
unsigned int nTimeSmart;
|
||||
/**
|
||||
* From me flag is set to 1 for transactions that were created by the wallet
|
||||
* on this Vexta node, and set to 0 for transactions that were created
|
||||
* externally and came in through the network or sendrawtransaction RPC.
|
||||
*/
|
||||
bool fFromMe;
|
||||
int64_t nOrderPos; //!< position in ordered transaction list
|
||||
std::multimap<int64_t, CWalletTx*>::const_iterator m_it_wtxOrdered;
|
||||
|
||||
// memory only
|
||||
enum AmountType { DEBIT, CREDIT, IMMATURE_CREDIT, AVAILABLE_CREDIT, AMOUNTTYPE_ENUM_ELEMENTS };
|
||||
CAmount GetCachableAmount(AmountType type, const isminefilter& filter, bool recalculate = false) const;
|
||||
mutable CachableAmount m_amounts[AMOUNTTYPE_ENUM_ELEMENTS];
|
||||
/**
|
||||
* This flag is true if all m_amounts caches are empty. This is particularly
|
||||
* useful in places where MarkDirty is conditionally called and the
|
||||
* condition can be expensive and thus can be skipped if the flag is true.
|
||||
* See MarkDestinationsDirty.
|
||||
*/
|
||||
mutable bool m_is_cache_empty{true};
|
||||
mutable bool fChangeCached;
|
||||
mutable bool fInMempool;
|
||||
mutable CAmount nChangeCached;
|
||||
|
||||
CWalletTx(const CWallet* wallet, CTransactionRef arg)
|
||||
: pwallet(wallet),
|
||||
tx(std::move(arg))
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
mapValue.clear();
|
||||
vOrderForm.clear();
|
||||
fTimeReceivedIsTxTime = false;
|
||||
nTimeReceived = 0;
|
||||
nTimeSmart = 0;
|
||||
fFromMe = false;
|
||||
fChangeCached = false;
|
||||
fInMempool = false;
|
||||
nChangeCached = 0;
|
||||
nOrderPos = -1;
|
||||
m_confirm = Confirmation{};
|
||||
}
|
||||
|
||||
CTransactionRef tx;
|
||||
|
||||
/** New transactions start as UNCONFIRMED. At BlockConnected,
|
||||
* they will transition to CONFIRMED. In case of reorg, at BlockDisconnected,
|
||||
* they roll back to UNCONFIRMED. If we detect a conflicting transaction at
|
||||
* block connection, we update conflicted tx and its dependencies as CONFLICTED.
|
||||
* If tx isn't confirmed and outside of 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 triplet of {block height/block hash/tx index in block}
|
||||
* at which tx has been confirmed. All three are set to 0 if tx is unconfirmed or abandoned.
|
||||
* Meaning of these fields changes with CONFLICTED state where they instead point to block hash
|
||||
* and block height of the deepest conflicting tx.
|
||||
*/
|
||||
struct Confirmation {
|
||||
Status status;
|
||||
int block_height;
|
||||
uint256 hashBlock;
|
||||
int nIndex;
|
||||
Confirmation(Status s = UNCONFIRMED, int b = 0, uint256 h = uint256(), int i = 0) : status(s), block_height(b), hashBlock(h), nIndex(i) {}
|
||||
};
|
||||
|
||||
Confirmation m_confirm;
|
||||
|
||||
template<typename Stream>
|
||||
void Serialize(Stream& s) const
|
||||
{
|
||||
mapValue_t mapValueCopy = mapValue;
|
||||
|
||||
mapValueCopy["fromaccount"] = "";
|
||||
WriteOrderPos(nOrderPos, mapValueCopy);
|
||||
if (nTimeSmart) {
|
||||
mapValueCopy["timesmart"] = strprintf("%u", nTimeSmart);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> dummy_vector1; //!< Used to be vMerkleBranch
|
||||
std::vector<uint8_t> dummy_vector2; //!< Used to be vtxPrev
|
||||
bool dummy_bool = false; //!< Used to be fSpent
|
||||
uint256 serializedHash = isAbandoned() ? ABANDON_HASH : m_confirm.hashBlock;
|
||||
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)
|
||||
{
|
||||
Init();
|
||||
|
||||
std::vector<uint256> dummy_vector1; //!< Used to be vMerkleBranch
|
||||
std::vector<CMerkleTx> dummy_vector2; //!< Used to be vtxPrev
|
||||
bool dummy_bool; //! Used to be fSpent
|
||||
int serializedIndex;
|
||||
s >> tx >> m_confirm.hashBlock >> dummy_vector1 >> serializedIndex >> 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) {
|
||||
setAbandoned();
|
||||
} else if (serializedIndex == -1) {
|
||||
setConflicted();
|
||||
} else if (!m_confirm.hashBlock.IsNull()) {
|
||||
m_confirm.nIndex = serializedIndex;
|
||||
setConfirmed();
|
||||
}
|
||||
|
||||
ReadOrderPos(nOrderPos, mapValue);
|
||||
nTimeSmart = mapValue.count("timesmart") ? (unsigned int)atoi64(mapValue["timesmart"]) : 0;
|
||||
|
||||
mapValue.erase("fromaccount");
|
||||
mapValue.erase("spent");
|
||||
mapValue.erase("n");
|
||||
mapValue.erase("timesmart");
|
||||
}
|
||||
|
||||
void SetTx(CTransactionRef arg)
|
||||
{
|
||||
tx = std::move(arg);
|
||||
}
|
||||
|
||||
//! make sure balances are recalculated
|
||||
void MarkDirty()
|
||||
{
|
||||
m_amounts[DEBIT].Reset();
|
||||
m_amounts[CREDIT].Reset();
|
||||
m_amounts[IMMATURE_CREDIT].Reset();
|
||||
m_amounts[AVAILABLE_CREDIT].Reset();
|
||||
fChangeCached = false;
|
||||
m_is_cache_empty = true;
|
||||
}
|
||||
|
||||
//! filter decides which addresses will count towards the debit
|
||||
CAmount GetDebit(const isminefilter& filter) const;
|
||||
CAmount GetCredit(const isminefilter& filter) const;
|
||||
CAmount GetImmatureCredit(bool fUseCache = true) const;
|
||||
// TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct
|
||||
// annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The
|
||||
// annotation "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid
|
||||
// having to resolve the issue of member access into incomplete type CWallet.
|
||||
CAmount GetAvailableCredit(bool fUseCache = true, const isminefilter& filter = ISMINE_SPENDABLE) const NO_THREAD_SAFETY_ANALYSIS;
|
||||
CAmount GetImmatureWatchOnlyCredit(const bool fUseCache = true) const;
|
||||
CAmount GetChange() const;
|
||||
|
||||
/** Get the marginal bytes if spending the specified output from this transaction */
|
||||
int GetSpendSize(unsigned int out, bool use_max_sig = false) const
|
||||
{
|
||||
return CalculateMaximumSignedInputSize(tx->vout[out], pwallet, use_max_sig);
|
||||
}
|
||||
|
||||
void GetAmounts(std::list<COutputEntry>& listReceived,
|
||||
std::list<COutputEntry>& listSent, CAmount& nFee, const isminefilter& filter) const;
|
||||
|
||||
bool IsFromMe(const isminefilter& filter) const
|
||||
{
|
||||
return (GetDebit(filter) > 0);
|
||||
}
|
||||
|
||||
/** True if only scriptSigs are different */
|
||||
bool IsEquivalentTo(const CWalletTx& tx) const;
|
||||
|
||||
bool InMempool() const;
|
||||
bool IsTrusted() const;
|
||||
|
||||
int64_t GetTxTime() const;
|
||||
|
||||
/** Pass this transaction to node for mempool insertion and relay to peers if flag set to true */
|
||||
bool SubmitMemoryPoolAndRelay(std::string& err_string, bool relay);
|
||||
|
||||
// TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct
|
||||
// annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The annotation
|
||||
// "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid having to
|
||||
// resolve the issue of member access into incomplete type CWallet. Note
|
||||
// that we still have the runtime check "AssertLockHeld(pwallet->cs_wallet)"
|
||||
// in place.
|
||||
std::set<uint256> GetConflicts() const NO_THREAD_SAFETY_ANALYSIS;
|
||||
|
||||
/**
|
||||
* Return depth of transaction in blockchain:
|
||||
* <0 : conflicts with a transaction this deep in the blockchain
|
||||
* 0 : in memory pool, waiting to be included in a block
|
||||
* >=1 : this many blocks deep in the main chain
|
||||
*/
|
||||
// TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct
|
||||
// annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The annotation
|
||||
// "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid having to
|
||||
// resolve the issue of member access into incomplete type CWallet. Note
|
||||
// that we still have the runtime check "AssertLockHeld(pwallet->cs_wallet)"
|
||||
// in place.
|
||||
int GetDepthInMainChain() const NO_THREAD_SAFETY_ANALYSIS;
|
||||
bool IsInMainChain() const { return GetDepthInMainChain() > 0; }
|
||||
|
||||
/**
|
||||
* @return number of blocks to maturity for this transaction:
|
||||
* 0 : is not a coinbase transaction, or is a mature coinbase transaction
|
||||
* >0 : is a coinbase transaction which matures in this many blocks
|
||||
*/
|
||||
int GetBlocksToMaturity() const;
|
||||
bool isAbandoned() const { return m_confirm.status == CWalletTx::ABANDONED; }
|
||||
void setAbandoned()
|
||||
{
|
||||
m_confirm.status = CWalletTx::ABANDONED;
|
||||
m_confirm.hashBlock = uint256();
|
||||
m_confirm.block_height = 0;
|
||||
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; }
|
||||
bool isConfirmed() const { return m_confirm.status == CWalletTx::CONFIRMED; }
|
||||
void setConfirmed() { m_confirm.status = CWalletTx::CONFIRMED; }
|
||||
const uint256& GetHash() const { return tx->GetHash(); }
|
||||
bool IsCoinBase() const { return tx->IsCoinBase(); }
|
||||
bool IsImmatureCoinBase() const;
|
||||
|
||||
// Disable copying of CWalletTx objects to prevent bugs where instances get
|
||||
// copied in and out of the mapWallet map, and fields are updated in the
|
||||
// wrong copy.
|
||||
CWalletTx(CWalletTx const &) = delete;
|
||||
void operator=(CWalletTx const &x) = delete;
|
||||
};
|
||||
|
||||
#endif // DIGIBYTE_WALLET_TRANSACTION_H
|
||||
Loading…
Reference in a new issue