Dash Core Source Documentation (0.16.0.1)

Find detailed information regarding the Dash Core source code.

privatesend-util.cpp
Go to the documentation of this file.
1 // Copyright (c) 2014-2019 The Dash Core developers
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <consensus/validation.h>
6 #include <policy/fees.h>
7 #include <policy/policy.h>
9 #include <script/sign.h>
10 #include <validation.h>
11 #include <wallet/fees.h>
12 
13 inline unsigned int GetSizeOfCompactSizeDiff(uint64_t nSizePrev, uint64_t nSizeNew)
14 {
15  assert(nSizePrev <= nSizeNew);
17 }
18 
20  reserveKey(pwallet)
21 {
23 }
24 
26 {
28 }
29 
31 {
33 }
34 
36 {
38 }
39 
40 
42 {
43  auto keyHolderPtr = std::unique_ptr<CKeyHolder>(new CKeyHolder(pwallet));
44  auto script = keyHolderPtr->GetScriptForDestination();
45 
47  storage.emplace_back(std::move(keyHolderPtr));
48  LogPrintf("CKeyHolderStorage::%s -- storage size %lld\n", __func__, storage.size());
49  return script;
50 }
51 
53 {
54  std::vector<std::unique_ptr<CKeyHolder> > tmp;
55  {
56  // don't hold cs_storage while calling KeepKey(), which might lock cs_wallet
58  std::swap(storage, tmp);
59  }
60 
61  if (!tmp.empty()) {
62  for (auto& key : tmp) {
63  key->KeepKey();
64  }
65  LogPrintf("CKeyHolderStorage::%s -- %lld keys kept\n", __func__, tmp.size());
66  }
67 }
68 
70 {
71  std::vector<std::unique_ptr<CKeyHolder> > tmp;
72  {
73  // don't hold cs_storage while calling ReturnKey(), which might lock cs_wallet
75  std::swap(storage, tmp);
76  }
77 
78  if (!tmp.empty()) {
79  for (auto& key : tmp) {
80  key->ReturnKey();
81  }
82  LogPrintf("CKeyHolderStorage::%s -- %lld keys returned\n", __func__, tmp.size());
83  }
84 }
85 
87  pTxBuilder(pTxBuilderIn),
88  key(pwalletIn),
89  nAmount(nAmountIn)
90 {
91  assert(pTxBuilder);
92  CPubKey pubKey;
93  key.GetReservedKey(pubKey, false);
95 }
96 
98 {
100  if (nNewAmount <= 0 || nNewAmount - nAmount > pTxBuilder->GetAmountLeft()) {
101  return false;
102  }
103  nAmount = nNewAmount;
104  return true;
105 }
106 
108  pwallet(pwalletIn),
109  dummyReserveKey(pwalletIn),
110  tallyItem(tallyItemIn)
111 {
112  // Generate a feerate which will be used to consider if the remainder is dust and will go into fees or not
114  // Generate a feerate which will be used by calculations of this class and also by CWallet::CreateTransaction
115  coinControl.m_feerate = std::max(::feeEstimator.estimateSmartFee((int)::nTxConfirmTarget, nullptr, true), payTxFee);
116  // Change always goes back to origin
117  coinControl.destChange = tallyItemIn.txdest;
118  // Only allow tallyItems inputs for tx creation
120  // Select all tallyItem outputs in the coinControl so that CreateTransaction knows what to use
121  for (const auto& outpoint : tallyItem.vecOutPoints) {
122  coinControl.Select(outpoint);
123  }
124  // Create dummy tx to calculate the exact required fees upfront for accurate amount and fee calculations
125  CMutableTransaction dummyTx;
126  // Get a comparable dummy scriptPubKey, avoid writting/flushing to the actual wallet db
127  CScript dummyScript;
128  {
130  WalletBatch dummyBatch(pwallet->GetDBHandle(), "r+", false);
131  dummyBatch.TxnBegin();
132  CPubKey dummyPubkey = pwallet->GenerateNewKey(dummyBatch, 0, false);
133  dummyBatch.TxnAbort();
134  dummyScript = ::GetScriptForDestination(dummyPubkey.GetID());
135  }
136  // Create dummy signatures for all inputs
137  SignatureData dummySignature;
138  ProduceSignature(DummySignatureCreator(pwallet), dummyScript, dummySignature);
139  for (auto out : tallyItem.vecOutPoints) {
140  dummyTx.vin.emplace_back(out, dummySignature.scriptSig);
141  }
142  // Calculate required bytes for the dummy tx with tallyItem's inputs only
144  // Calculate the output size
146  // Just to make sure..
147  Clear();
148 }
149 
151 {
152  Clear();
153 }
154 
156 {
157  std::vector<std::unique_ptr<CTransactionBuilderOutput>> vecOutputsTmp;
158  {
159  // Don't hold cs_outputs while clearing the outputs which might indirectly call lock cs_wallet
160  LOCK(cs_outputs);
161  std::swap(vecOutputs, vecOutputsTmp);
162  vecOutputs.clear();
163  }
164 
165  for (auto& key : vecOutputsTmp) {
166  if (fKeepKeys) {
167  key->KeepKey();
168  } else {
169  key->ReturnKey();
170  }
171  }
172  // Always return this key just to make sure..
174 }
175 
177 {
178  if (nAmountOutput < 0) {
179  return false;
180  }
181  // Adding another output can change the serialized size of the vout size hence + GetSizeOfCompactSizeDiff()
182  unsigned int nBytes = GetBytesTotal() + nBytesOutput + GetSizeOfCompactSizeDiff(1);
183  return GetAmountLeft(GetAmountInitial(), GetAmountUsed() + nAmountOutput, GetFee(nBytes)) >= 0;
184 }
185 
186 bool CTransactionBuilder::CouldAddOutputs(const std::vector<CAmount>& vecOutputAmounts) const
187 {
188  CAmount nAmountAdditional{0};
189  assert(vecOutputAmounts.size() < INT_MAX);
190  int nBytesAdditional = nBytesOutput * (int)vecOutputAmounts.size();
191  for (const auto nAmountOutput : vecOutputAmounts) {
192  if (nAmountOutput < 0) {
193  return false;
194  }
195  nAmountAdditional += nAmountOutput;
196  }
197  // Adding other outputs can change the serialized size of the vout size hence + GetSizeOfCompactSizeDiff()
198  unsigned int nBytes = GetBytesTotal() + nBytesAdditional + GetSizeOfCompactSizeDiff(vecOutputAmounts.size());
199  return GetAmountLeft(GetAmountInitial(), GetAmountUsed() + nAmountAdditional, GetFee(nBytes)) >= 0;
200 }
201 
203 {
204  LOCK(cs_outputs);
205  if (CouldAddOutput(nAmountOutput)) {
206  vecOutputs.push_back(std::make_unique<CTransactionBuilderOutput>(this, pwallet, nAmountOutput));
207  return vecOutputs.back().get();
208  }
209  return nullptr;
210 }
211 
213 {
214  // Adding other outputs can change the serialized size of the vout size hence + GetSizeOfCompactSizeDiff()
216 }
217 
218 CAmount CTransactionBuilder::GetAmountLeft(const CAmount nAmountInitial, const CAmount nAmountUsed, const CAmount nFee)
219 {
220  return nAmountInitial - nAmountUsed - nFee;
221 }
222 
224 {
225  CAmount nAmountUsed{0};
226  for (const auto& out : vecOutputs) {
227  nAmountUsed += out->GetAmount();
228  }
229  return nAmountUsed;
230 }
231 
232 CAmount CTransactionBuilder::GetFee(unsigned int nBytes) const
233 {
234  CAmount nFeeCalc = coinControl.m_feerate->GetFee(nBytes);
235  CAmount nRequiredFee = GetRequiredFee(nBytes);
236  if (nRequiredFee > nFeeCalc) {
237  nFeeCalc = nRequiredFee;
238  }
239  if (nFeeCalc > ::maxTxFee) {
240  nFeeCalc = ::maxTxFee;
241  }
242  return nFeeCalc;
243 }
244 
246 {
247  size_t nSize = vecOutputs.size();
248  unsigned int ret = ::GetSizeOfCompactSizeDiff(nSize, nSize + nAdd);
249  assert(ret <= INT_MAX);
250  return (int)ret;
251 }
252 
254 {
256 }
257 
258 bool CTransactionBuilder::Commit(std::string& strResult)
259 {
260  CWalletTx wtx;
261  CAmount nFeeRet = 0;
262  int nChangePosRet = -1;
263 
264  // Transform the outputs to the format CWallet::CreateTransaction requires
265  std::vector<CRecipient> vecSend;
266  {
267  LOCK(cs_outputs);
268  vecSend.reserve(vecOutputs.size());
269  for (const auto& out : vecOutputs) {
270  vecSend.push_back((CRecipient){out->GetScript(), out->GetAmount(), false});
271  }
272  }
273 
274  if (!pwallet->CreateTransaction(vecSend, wtx, dummyReserveKey, nFeeRet, nChangePosRet, strResult, coinControl)) {
275  return false;
276  }
277 
278  CAmount nAmountLeft = GetAmountLeft();
279  bool fDust = IsDust(nAmountLeft);
280  // If there is a either remainder which is considered to be dust (will be added to fee in this case) or no amount left there should be no change output, return if there is a change output.
281  if (nChangePosRet != -1 && fDust) {
282  strResult = strprintf("Unexpected change output %s at position %d", wtx.tx->vout[nChangePosRet].ToString(), nChangePosRet);
283  return false;
284  }
285 
286  // If there is a remainder which is not considered to be dust it should end up in a change output, return if not.
287  if (nChangePosRet == -1 && !fDust) {
288  strResult = strprintf("Change output missing: %d", nAmountLeft);
289  return false;
290  }
291 
292  CAmount nFeeAdditional{0};
293  unsigned int nBytesAdditional{0};
294 
295  if (fDust) {
296  nFeeAdditional = nAmountLeft;
297  } else {
298  // Add a change output and GetSizeOfCompactSizeDiff(1) as another output can changes the serialized size of the vout size in CTransaction
299  nBytesAdditional = nBytesOutput + GetSizeOfCompactSizeDiff(1);
300  }
301 
302  // If the calculated fee does not match the fee returned by CreateTransaction aka if this check fails something is wrong!
303  CAmount nFeeCalc = GetFee(GetBytesTotal() + nBytesAdditional) + nFeeAdditional;
304  if (nFeeRet != nFeeCalc) {
305  strResult = strprintf("Fee validation failed -> nFeeRet: %d, nFeeCalc: %d, nFeeAdditional: %d, nBytesAdditional: %d, %s", nFeeRet, nFeeCalc, nFeeAdditional, nBytesAdditional, ToString());
306  return false;
307  }
308 
309  CValidationState state;
310  if (!pwallet->CommitTransaction(wtx, dummyReserveKey, g_connman.get(), state)) {
311  strResult = state.GetRejectReason();
312  return false;
313  }
314 
315  fKeepKeys = true;
316 
317  strResult = wtx.GetHash().ToString();
318 
319  return true;
320 }
321 
322 std::string CTransactionBuilder::ToString() const
323 {
324  return strprintf("CTransactionBuilder(Amount initial: %d, Amount left: %d, Bytes base: %d, Bytes output: %d, Bytes total: %d, Amount used: %d, Outputs: %d, Fee rate: %d, Discard fee rate: %d, Fee: %d)",
326  GetAmountLeft(),
327  nBytesBase,
328  nBytesOutput,
329  GetBytesTotal(),
330  GetAmountUsed(),
331  CountOutputs(),
332  coinControl.m_feerate->GetFeePerK(),
333  coinControl.m_discard_feerate->GetFeePerK(),
334  GetFee(GetBytesTotal()));
335 }
std::vector< std::unique_ptr< CTransactionBuilderOutput > > vecOutputs
Contains all outputs already added to the transaction.
CTransactionBuilderOutput(CTransactionBuilder *pTxBuilderIn, CWallet *pwalletIn, CAmount nAmountIn)
CFeeRate GetDiscardRate(const CBlockPolicyEstimator &estimator)
Return the maximum feerate for discarding change.
Definition: fees.cpp:78
bool fKeepKeys
Call KeepKey for all keys in destructor if fKeepKeys is true, call ReturnKey for all key if its false...
bool Commit(std::string &strResult)
Create and Commit the transaction to the wallet.
CTransactionBuilder(CWallet *pwalletIn, const CompactTallyItem &tallyItemIn)
CCoinControl coinControl
See CTransactionBuilder() for initialization.
CCriticalSection cs_wallet
Definition: wallet.h:836
#define strprintf
Definition: tinyformat.h:1066
const uint256 & GetHash() const
Definition: wallet.h:272
CAmount maxTxFee
Absolute maximum transaction fee (in duffs) used by wallet and mempool (rejects high fee in sendrawtr...
Definition: validation.cpp:247
CScript scriptSig
Definition: sign.h:63
std::vector< CTxIn > vin
Definition: transaction.h:293
size_t GetSerializeSize(const T &t, int nType, int nVersion=0)
Definition: serialize.h:1295
int nBytesOutput
Contains the number of bytes required to add one output.
std::vector< COutPoint > vecOutPoints
Definition: wallet.h:111
unsigned int GetSizeOfCompactSize(uint64_t nSize)
Compact Size size < 253 – 1 byte size <= USHRT_MAX – 3 bytes (253 + 2 bytes) size <= UINT_MAX – 5 ...
Definition: serialize.h:225
bool TxnBegin()
Begin a new transaction.
Definition: walletdb.cpp:900
CAmount GetRequiredFee(unsigned int nTxBytes)
Return the minimum required fee taking into account the floating relay fee and user set minimum trans...
Definition: fees.cpp:16
bool ProduceSignature(const BaseSignatureCreator &creator, const CScript &fromPubKey, SignatureData &sigdata)
Produce a script signature using a generic signature creator.
Definition: sign.cpp:124
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:149
bool CouldAddOutputs(const std::vector< CAmount > &vecOutputAmounts) const
Check if its possible to add multiple outputs as vector of amounts. Returns true if its possible to a...
boost::optional< CFeeRate > m_feerate
Override the default payTxFee if set.
Definition: coincontrol.h:41
Access to the wallet database.
Definition: walletdb.h:96
boost::optional< CFeeRate > m_discard_feerate
Override the discard feerate estimation with m_discard_feerate in CreateTransaction if set...
Definition: coincontrol.h:43
CReserveKey key
Reserve key where the amount of this output will end up.
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
CAmount GetAmountLeft() const
Get the amount currently left to add more outputs. Does respect fees.
Enables simple transaction generation for a given CWallet object.
CBlockPolicyEstimator feeEstimator
Definition: validation.cpp:249
CAmount GetAmountUsed() const
Get the amount currently used by added outputs. Does not include fees.
CAmount GetAmountInitial() const
Get amount we had available when we started.
unsigned int nTxConfirmTarget
Definition: wallet.cpp:96
#define LogPrintf(...)
Definition: util.h:203
CompactTallyItem tallyItem
Contains all utxos available to generate this transactions. They are all from the same address...
CTransactionRef tx
Definition: wallet.h:210
CScript AddKey(CWallet *pwalletIn)
CKeyHolder(CWallet *pwalletIn)
#define LOCK(cs)
Definition: sync.h:178
CFeeRate estimateSmartFee(int confTarget, FeeCalculation *feeCalc, bool conservative) const
Estimate feerate needed to get be included in a block within confTarget blocks.
Definition: fees.cpp:819
CAmount nAmount
Amount this output will receive.
CTxDestination destChange
Definition: coincontrol.h:31
void Select(const COutPoint &output)
Definition: coincontrol.h:81
An encapsulated public key.
Definition: pubkey.h:30
bool fAllowOtherInputs
If false, allows unselected inputs, but requires all selected inputs be used if fAllowOtherInputs is ...
Definition: coincontrol.h:33
std::string GetRejectReason() const
Definition: validation.h:81
int nBytesBase
Contains the number of bytes required for a transaction with only the inputs of tallyItems, no outputs.
CScript GetScriptForDestination() const
WalletDatabase & GetDBHandle()
Get database handle used by this wallet.
Definition: wallet.h:841
unsigned int GetBytesTotal() const
Get the total number of bytes used already by this transaction.
CReserveKey dummyReserveKey
Dummy since we anyway use tallyItem&#39;s destination as change destination in coincontrol.
An output of a transaction.
Definition: transaction.h:144
std::vector< std::unique_ptr< CKeyHolder > > storage
std::string ToString() const
Convert to a string.
std::string ToString() const
Definition: uint256.cpp:62
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
Definition: standard.cpp:256
CTxDestination txdest
Definition: wallet.h:109
unsigned int GetSizeOfCompactSizeDiff(uint64_t nSizePrev, uint64_t nSizeNew)
A transaction with a bunch of additional info that only the owner cares about.
Definition: wallet.h:280
CPubKey pubKey
void KeepKey()
Definition: wallet.cpp:4740
bool IsDust(CAmount nAmount) const
Check if an amounts should be considered as dust.
Used by CTransactionBuilder to represent its transaction outputs.
CWallet * pwallet
Wallet the transaction will be build for.
Capture information about block/transaction validation.
Definition: validation.h:22
CAmount GetFee(unsigned int nBytes) const
Get fees based on the number of bytes and the feerate set in CoinControl.
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:389
bool CouldAddOutput(CAmount nAmountOutput) const
Check it would be possible to add a single output with the amount nAmount. Returns true if its possib...
CReserveKey reserveKey
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:14
int CountOutputs() const
Get the total number of added outputs.
bool CreateTransaction(const std::vector< CRecipient > &vecSend, CWalletTx &wtxNew, CReserveKey &reservekey, CAmount &nFeeRet, int &nChangePosInOut, std::string &strFailReason, const CCoinControl &coin_control, bool sign=true, int nExtraPayloadSize=0)
Create a new transaction paying the recipients with a set of coins selected by SelectCoins(); Also cr...
Definition: wallet.cpp:3658
CTransactionBuilder * pTxBuilder
Used for amount updates.
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances...
Definition: wallet.h:715
std::unique_ptr< CConnman > g_connman
Definition: init.cpp:97
CPubKey GenerateNewKey(WalletBatch &batch, uint32_t nAccountIndex, bool fInternal)
keystore implementation Generate a new key
Definition: wallet.cpp:187
CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE)
Transaction fee set by the user.
CCriticalSection cs_outputs
Protect vecOutputs.
bool IsDust(const CTxOut &txout, const CFeeRate &dustRelayFeeIn)
Definition: policy.cpp:35
A mutable version of CTransaction.
Definition: transaction.h:291
bool GetReservedKey(CPubKey &pubkey, bool fInternalIn)
Definition: wallet.cpp:4721
void ReturnKey()
Definition: wallet.cpp:4749
CScript script
ScriptPubKey of this output.
CCriticalSection cs_storage
void Clear()
Clear the output vector and keep/return the included keys depending on the value of fKeepKeys...
CTransactionBuilderOutput * AddOutput(CAmount nAmountOutput=0)
Add an output with the amount nAmount. Returns a pointer to the output if it could be added and nullp...
A signature creator that just produces 72-byte empty signatures.
Definition: sign.h:55
int GetSizeOfCompactSizeDiff(size_t nAdd) const
Helper to get GetSizeOfCompactSizeDiff(vecOutputs.size(), vecOutputs.size() + nAdd) ...
bool CommitTransaction(CWalletTx &wtxNew, CReserveKey &reservekey, CConnman *connman, CValidationState &state)
Call after CreateTransaction unless you want to abort.
Definition: wallet.cpp:4089
bool UpdateAmount(CAmount nAmount)
Try update the amount of this output. Returns true if it was successful and false if not (e...
Released under the MIT license