Skip to content

Commit b6ccbef

Browse files
committed
Fix bug in CreateTransaction
1 parent ba23d4f commit b6ccbef

File tree

1 file changed

+100
-22
lines changed

1 file changed

+100
-22
lines changed

src/wallet/wallet.cpp

Lines changed: 100 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1673,6 +1673,8 @@ bool CWallet::SelectCoins(int64_t nTargetValue, unsigned int nSpendTime, set<pai
16731673
}
16741674

16751675
if (contract) {
1676+
LogPrint(BCLog::LogFlags::ESTIMATEFEE, "INFO %s: Contract is included so SelectSmallestCoins will be used.", __func__);
1677+
16761678
return (SelectSmallestCoins(nTargetValue, nSpendTime, 1, 10, vCoins, setCoinsRet, nValueRet) ||
16771679
SelectSmallestCoins(nTargetValue, nSpendTime, 1, 1, vCoins, setCoinsRet, nValueRet) ||
16781680
SelectSmallestCoins(nTargetValue, nSpendTime, 0, 1, vCoins, setCoinsRet, nValueRet));
@@ -1795,12 +1797,15 @@ bool CWallet::SelectCoinsForStaking(unsigned int nSpendTime, std::vector<pair<co
17951797
return true;
17961798
}
17971799

1798-
bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend, set<pair<const CWalletTx*,unsigned int>>& setCoins,
1800+
bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend, set<pair<const CWalletTx*,unsigned int>>& setCoins_in,
17991801
CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, const CCoinControl* coinControl)
18001802
{
18011803

18021804
int64_t nValueOut = 0;
18031805
int64_t message_fee = 0;
1806+
set<pair<const CWalletTx*,unsigned int>> setCoins_out;
1807+
1808+
bool provided_coin_set = !setCoins_in.empty();
18041809

18051810
for (auto const& s : vecSend)
18061811
{
@@ -1833,10 +1838,13 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
18331838
{
18341839
wtxNew.vin.clear();
18351840
wtxNew.vout.clear();
1841+
setCoins_out.clear();
18361842
wtxNew.fFromMe = true;
18371843

18381844
int64_t nTotalValue = nValueOut + nFeeRet;
1839-
double dPriority = 0;
1845+
// dPriority is not currently used. Commented out.
1846+
//double dPriority = 0;
1847+
18401848
// vouts to the payees
18411849
for (auto const& s : vecSend)
18421850
wtxNew.vout.emplace_back(s.second, s.first);
@@ -1850,7 +1858,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
18501858
int64_t nValueIn = 0;
18511859

18521860
// If provided coin set is empty, choose coins to use.
1853-
if (!setCoins.size())
1861+
if (!provided_coin_set)
18541862
{
18551863
// If the transaction contains a contract, we want to select the
18561864
// smallest UTXOs available:
@@ -1862,29 +1870,75 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
18621870
&& !wtxNew.vContracts.empty()
18631871
&& wtxNew.vContracts[0].m_type != GRC::ContractType::MESSAGE;
18641872

1865-
if (!SelectCoins(nTotalValue, wtxNew.nTime, setCoins, nValueIn, coinControl, contract)) {
1873+
// Notice that setCoins_out is that set PRODUCED by SelectCoins. Tying this to the input
1874+
// parameter of CreateTransaction was a major bug here before. It is now separated.
1875+
if (!SelectCoins(nTotalValue, wtxNew.nTime, setCoins_out, nValueIn, coinControl, contract)) {
18661876
return error("%s: Failed to select coins", __func__);
18671877
}
1878+
1879+
if (LogInstance().WillLogCategory(BCLog::LogFlags::ESTIMATEFEE))
1880+
{
1881+
CAmount setcoins_total = 0;
1882+
1883+
for (const auto& output: setCoins_out)
1884+
{
1885+
setcoins_total += output.first->vout[output.second].nValue;
1886+
}
1887+
1888+
LogPrintf("INFO %s: Just after SelectCoins: "
1889+
"nTotalValue = %s, nValueIn = %s, nValueOut = %s, setCoins total = %s.",
1890+
__func__,
1891+
FormatMoney(nTotalValue),
1892+
FormatMoney(nValueIn),
1893+
FormatMoney(nValueOut),
1894+
FormatMoney(setcoins_total));
1895+
}
1896+
1897+
// Compute dPriority on automatically selected coins.
1898+
/*
1899+
for (auto const& input : setCoins_out)
1900+
{
1901+
int64_t nCredit = input.first->vout[input.second].nValue;
1902+
dPriority += (double) nCredit * input.first->GetDepthInMainChain();
1903+
}
1904+
*/
18681905
}
18691906
else
18701907
{
1871-
// Add up input value for the provided set of coins.
1872-
for (auto const& input : setCoins)
1908+
// Add up input value for the provided set of coins, and also compute dPriority. (dPriority is
1909+
// commented out because it is not actually used right now.
1910+
for (auto const& input : setCoins_in)
18731911
{
1874-
nValueIn += input.first->vout[input.second].nValue;
1912+
int64_t nCredit = input.first->vout[input.second].nValue;
1913+
//dPriority += (double) nCredit * input.first->GetDepthInMainChain();
1914+
nValueIn += nCredit;
18751915
}
18761916
}
18771917

1878-
for (auto const& pcoin : setCoins)
1918+
int64_t nChange = nValueIn - nValueOut - nFeeRet;
1919+
1920+
// Note: In the case where CreateTransaction is called with a provided input set of coins,
1921+
// if the nValueIn of those coins is sufficient to cover the minimum nTransactionFee that starts
1922+
// the while loop, it will pass the first iteration. If the size of the transaction causes the nFeeRet
1923+
// to elevate and a second pass shows that the nValueOut + required fee is greater than that available
1924+
// i.e. negative change, then the loop is exited with an error. The reasoning for this is that
1925+
// in the case of no provided coin set, SelectTransaction above will be given the change to modify its
1926+
// selection to cover the increased fees, hopefully converging on an appropriate solution. In the case
1927+
// of a provided set of inputs, that set is immutable for this transaction, so no point in continuing.
1928+
if (provided_coin_set && nChange < 0)
18791929
{
1880-
int64_t nCredit = pcoin.first->vout[pcoin.second].nValue;
1881-
dPriority += (double)nCredit * pcoin.first->GetDepthInMainChain();
1930+
return error("%s: Total value of inputs, %s, cannot cover the transaction fees of %s. "
1931+
"CreateTransaction aborted.",
1932+
__func__,
1933+
FormatMoney(nValueIn),
1934+
FormatMoney(nFeeRet));
18821935
}
18831936

1884-
int64_t nChange = nValueIn - nValueOut - nFeeRet;
1885-
1886-
LogPrint(BCLog::LogFlags::ESTIMATEFEE, "INFO %s: Before CENT test: nChange = %s, nFeeRet = %s.",
1937+
LogPrint(BCLog::LogFlags::ESTIMATEFEE, "INFO %s: Before CENT test: nValueIn = %s, nValueOut = %s, "
1938+
"nChange = %s, nFeeRet = %s.",
18871939
__func__,
1940+
FormatMoney(nValueIn),
1941+
FormatMoney(nValueOut),
18881942
FormatMoney(nChange),
18891943
FormatMoney(nFeeRet));
18901944

@@ -1937,26 +1991,50 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
19371991
wtxNew.vout.insert(position, CTxOut(nChange, scriptChange));
19381992
}
19391993
else
1994+
{
19401995
reservekey.ReturnKey();
1996+
}
19411997

1942-
// Fill vin
1943-
for (auto const& coin : setCoins)
1944-
wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
1998+
if (setCoins_in.size())
1999+
{
2000+
// Fill vin from provided inputs
2001+
for (auto const& coin : setCoins_in)
2002+
{
2003+
wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
2004+
}
19452005

1946-
// Sign
1947-
int nIn = 0;
1948-
for (auto const& coin : setCoins)
1949-
if (!SignSignature(*this, *coin.first, wtxNew, nIn++)) {
1950-
return error("%s: Failed to sign tx", __func__);
2006+
// Sign
2007+
int nIn = 0;
2008+
for (auto const& coin : setCoins_in)
2009+
if (!SignSignature(*this, *coin.first, wtxNew, nIn++)) {
2010+
return error("%s: Failed to sign tx", __func__);
2011+
}
2012+
}
2013+
else // use setCoins_out from SelectCoins as the inputs
2014+
{
2015+
// Fill vin from provided inputs
2016+
for (auto const& coin : setCoins_out)
2017+
{
2018+
wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
19512019
}
19522020

2021+
// Sign
2022+
int nIn = 0;
2023+
for (auto const& coin : setCoins_out)
2024+
if (!SignSignature(*this, *coin.first, wtxNew, nIn++))
2025+
{
2026+
return error("%s: Failed to sign tx", __func__);
2027+
}
2028+
}
2029+
19532030
// Limit size
19542031
unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION);
19552032
if (nBytes >= MAX_STANDARD_TX_SIZE) {
19562033
return error("%s: tx size %d greater than standard %d", __func__, nBytes, MAX_STANDARD_TX_SIZE);
19572034
}
19582035

1959-
dPriority /= nBytes;
2036+
// dPriority is not currently used.
2037+
//dPriority /= nBytes;
19602038

19612039
// Check that enough fee is included
19622040
int64_t nPayFee = nTransactionFee * (1 + (int64_t)nBytes / 1000);

0 commit comments

Comments
 (0)