5
5
#include < consensus/validation.h>
6
6
#include < interfaces/chain.h>
7
7
#include < policy/policy.h>
8
+ #include < script/signingprovider.h>
8
9
#include < util/check.h>
9
10
#include < util/fees.h>
10
11
#include < util/moneystr.h>
@@ -31,21 +32,27 @@ std::string COutput::ToString() const
31
32
return strprintf (" COutput(%s, %d, %d) [%s]" , tx->GetHash ().ToString (), i, nDepth, FormatMoney (tx->tx ->vout [i].nValue ));
32
33
}
33
34
34
- int CalculateMaximumSignedInputSize (const CTxOut& txout, const CWallet* wallet , bool use_max_sig)
35
+ int CalculateMaximumSignedInputSize (const CTxOut& txout, const SigningProvider* provider , bool use_max_sig)
35
36
{
36
37
CMutableTransaction txn;
37
38
txn.vin .push_back (CTxIn (COutPoint ()));
38
- if (!wallet-> DummySignInput (txn.vin [0 ], txout, use_max_sig)) {
39
+ if (!provider || ! DummySignInput (*provider, txn.vin [0 ], txout, use_max_sig)) {
39
40
return -1 ;
40
41
}
41
42
return GetVirtualTransactionInputSize (txn.vin [0 ]);
42
43
}
43
44
45
+ int CalculateMaximumSignedInputSize (const CTxOut& txout, const CWallet* wallet, bool use_max_sig)
46
+ {
47
+ const std::unique_ptr<SigningProvider> provider = wallet->GetSolvingProvider (txout.scriptPubKey );
48
+ return CalculateMaximumSignedInputSize (txout, provider.get (), use_max_sig);
49
+ }
50
+
44
51
// txouts needs to be in the order of tx.vin
45
- TxSize CalculateMaximumSignedTxSize (const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts, bool use_max_sig )
52
+ TxSize CalculateMaximumSignedTxSize (const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts, const CCoinControl* coin_control )
46
53
{
47
54
CMutableTransaction txNew (tx);
48
- if (!wallet->DummySignTx (txNew, txouts, use_max_sig )) {
55
+ if (!wallet->DummySignTx (txNew, txouts, coin_control )) {
49
56
return TxSize{-1 , -1 };
50
57
}
51
58
CTransaction ctx (txNew);
@@ -54,19 +61,27 @@ TxSize CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *walle
54
61
return TxSize{vsize, weight};
55
62
}
56
63
57
- TxSize CalculateMaximumSignedTxSize (const CTransaction &tx, const CWallet *wallet, bool use_max_sig )
64
+ TxSize CalculateMaximumSignedTxSize (const CTransaction &tx, const CWallet *wallet, const CCoinControl* coin_control )
58
65
{
59
66
std::vector<CTxOut> txouts;
67
+ // Look up the inputs. The inputs are either in the wallet, or in coin_control.
60
68
for (const CTxIn& input : tx.vin ) {
61
69
const auto mi = wallet->mapWallet .find (input.prevout .hash );
62
70
// Can not estimate size without knowing the input details
63
- if (mi == wallet->mapWallet .end ()) {
71
+ if (mi != wallet->mapWallet .end ()) {
72
+ assert (input.prevout .n < mi->second .tx ->vout .size ());
73
+ txouts.emplace_back (mi->second .tx ->vout .at (input.prevout .n ));
74
+ } else if (coin_control) {
75
+ CTxOut txout;
76
+ if (!coin_control->GetExternalOutput (input.prevout , txout)) {
77
+ return TxSize{-1 , -1 };
78
+ }
79
+ txouts.emplace_back (txout);
80
+ } else {
64
81
return TxSize{-1 , -1 };
65
82
}
66
- assert (input.prevout .n < mi->second .tx ->vout .size ());
67
- txouts.emplace_back (mi->second .tx ->vout [input.prevout .n ]);
68
83
}
69
- return CalculateMaximumSignedTxSize (tx, wallet, txouts, use_max_sig );
84
+ return CalculateMaximumSignedTxSize (tx, wallet, txouts, coin_control );
70
85
}
71
86
72
87
void AvailableCoins (const CWallet& wallet, std::vector<COutput>& vCoins, const CCoinControl* coinControl, const CAmount& nMinimumAmount, const CAmount& nMaximumAmount, const CAmount& nMinimumSumAmount, const uint64_t nMaximumCount)
@@ -435,32 +450,40 @@ bool SelectCoins(const CWallet& wallet, const std::vector<COutput>& vAvailableCo
435
450
436
451
std::vector<COutPoint> vPresetInputs;
437
452
coin_control.ListSelected (vPresetInputs);
438
- for (const COutPoint& outpoint : vPresetInputs)
439
- {
453
+ for (const COutPoint& outpoint : vPresetInputs) {
454
+ int input_bytes = -1 ;
455
+ CTxOut txout;
440
456
std::map<uint256, CWalletTx>::const_iterator it = wallet.mapWallet .find (outpoint.hash );
441
- if (it != wallet.mapWallet .end ())
442
- {
457
+ if (it != wallet.mapWallet .end ()) {
443
458
const CWalletTx& wtx = it->second ;
444
459
// Clearly invalid input, fail
445
460
if (wtx.tx ->vout .size () <= outpoint.n ) {
446
461
return false ;
447
462
}
448
- // Just to calculate the marginal byte size
449
- CInputCoin coin (wtx.tx , outpoint.n , GetTxSpendSize (wallet, wtx, outpoint.n , false ));
450
- nValueFromPresetInputs += coin.txout .nValue ;
451
- if (coin.m_input_bytes <= 0 ) {
452
- return false ; // Not solvable, can't estimate size for fee
453
- }
454
- coin.effective_value = coin.txout .nValue - coin_selection_params.m_effective_feerate .GetFee (coin.m_input_bytes );
455
- if (coin_selection_params.m_subtract_fee_outputs ) {
456
- value_to_select -= coin.txout .nValue ;
457
- } else {
458
- value_to_select -= coin.effective_value ;
463
+ input_bytes = GetTxSpendSize (wallet, wtx, outpoint.n , false );
464
+ txout = wtx.tx ->vout .at (outpoint.n );
465
+ }
466
+ if (input_bytes == -1 ) {
467
+ // The input is external. We either did not find the tx in mapWallet, or we did but couldn't compute the input size with wallet data
468
+ if (!coin_control.GetExternalOutput (outpoint, txout)) {
469
+ // Not ours, and we don't have solving data.
470
+ return false ;
459
471
}
460
- setPresetCoins.insert (coin);
472
+ input_bytes = CalculateMaximumSignedInputSize (txout, &coin_control.m_external_provider , /* use_max_sig */ true );
473
+ }
474
+
475
+ CInputCoin coin (outpoint, txout, input_bytes);
476
+ nValueFromPresetInputs += coin.txout .nValue ;
477
+ if (coin.m_input_bytes <= 0 ) {
478
+ return false ; // Not solvable, can't estimate size for fee
479
+ }
480
+ coin.effective_value = coin.txout .nValue - coin_selection_params.m_effective_feerate .GetFee (coin.m_input_bytes );
481
+ if (coin_selection_params.m_subtract_fee_outputs ) {
482
+ value_to_select -= coin.txout .nValue ;
461
483
} else {
462
- return false ; // TODO: Allow non-wallet inputs
484
+ value_to_select -= coin. effective_value ;
463
485
}
486
+ setPresetCoins.insert (coin);
464
487
}
465
488
466
489
// remove preset inputs from vCoins so that Coin Selection doesn't pick them.
@@ -788,10 +811,10 @@ static bool CreateTransactionInternal(
788
811
}
789
812
790
813
// Calculate the transaction fee
791
- TxSize tx_sizes = CalculateMaximumSignedTxSize (CTransaction (txNew), &wallet, coin_control. fAllowWatchOnly );
814
+ TxSize tx_sizes = CalculateMaximumSignedTxSize (CTransaction (txNew), &wallet, & coin_control);
792
815
int nBytes = tx_sizes.vsize ;
793
816
if (nBytes < 0 ) {
794
- error = _ (" Signing transaction failed " );
817
+ error = _ (" Missing solving data for estimating transaction size " );
795
818
return false ;
796
819
}
797
820
nFeeRet = coin_selection_params.m_effective_feerate .GetFee (nBytes);
@@ -813,7 +836,7 @@ static bool CreateTransactionInternal(
813
836
txNew.vout .erase (change_position);
814
837
815
838
// Because we have dropped this change, the tx size and required fee will be different, so let's recalculate those
816
- tx_sizes = CalculateMaximumSignedTxSize (CTransaction (txNew), &wallet, coin_control. fAllowWatchOnly );
839
+ tx_sizes = CalculateMaximumSignedTxSize (CTransaction (txNew), &wallet, & coin_control);
817
840
nBytes = tx_sizes.vsize ;
818
841
fee_needed = coin_selection_params.m_effective_feerate .GetFee (nBytes);
819
842
}
0 commit comments