@@ -126,6 +126,18 @@ COutPoint GetOutpointWithAmount(const CTransaction& tx, CAmount outpointValue)
126126 return {};
127127}
128128
129+ static bool IsSpentOnFork (const COutput& coin, std::initializer_list<std::shared_ptr<CBlock>> forkchain = {})
130+ {
131+ for (const auto & block : forkchain) {
132+ const auto & usedOutput = block->vtx [1 ]->vin .at (0 ).prevout ;
133+ if (coin.tx ->GetHash () == usedOutput.hash && coin.i == (int )usedOutput.n ) {
134+ // spent on fork
135+ return true ;
136+ }
137+ }
138+ return false ;
139+ }
140+
129141std::shared_ptr<CBlock> CreateBlockInternal (CWallet* pwalletMain, const std::vector<CMutableTransaction>& txns = {},
130142 CBlockIndex* customPrevBlock = nullptr ,
131143 std::initializer_list<std::shared_ptr<CBlock>> forkchain = {})
@@ -135,26 +147,15 @@ std::shared_ptr<CBlock> CreateBlockInternal(CWallet* pwalletMain, const std::vec
135147
136148 // Remove any utxo which is not deeper than 120 blocks (for the same reasoning
137149 // used when selecting tx inputs in CreateAndCommitTx)
138- for (auto it = availableCoins.begin (); it != availableCoins.end () ;) {
139- if (it->nDepth <= 120 ) {
140- it = availableCoins.erase (it);
141- } else {
142- it++;
143- }
144- }
145-
146150 // Also, as the wallet is not prepared to follow several chains at the same time,
147151 // need to manually remove from the stakeable utxo set every already used
148152 // coinstake inputs on the previous blocks of the parallel chain so they
149153 // are not used again.
150- for (const auto & block : forkchain) {
151- auto usedOutput = block->vtx [1 ]->vin .at (0 ).prevout ;
152- for (auto it = availableCoins.begin (); it != availableCoins.end () ; it++) {
153- if (it->tx ->GetHash () == usedOutput.hash &&
154- it->i == (int ) usedOutput.n ) {
155- availableCoins.erase (it);
156- break ;
157- }
154+ for (auto it = availableCoins.begin (); it != availableCoins.end () ;) {
155+ if (it->nDepth <= 120 || IsSpentOnFork (*it, forkchain)) {
156+ it = availableCoins.erase (it);
157+ } else {
158+ it++;
158159 }
159160 }
160161
@@ -179,6 +180,20 @@ std::shared_ptr<CBlock> CreateBlockInternal(CWallet* pwalletMain, const std::vec
179180 return pblock;
180181}
181182
183+ static COutput GetUnspentCoin (CWallet* pwallet, std::initializer_list<std::shared_ptr<CBlock>> forkchain = {})
184+ {
185+ std::vector<COutput> availableCoins;
186+ CWallet::AvailableCoinsFilter coinsFilter;
187+ coinsFilter.minDepth = 120 ;
188+ BOOST_CHECK (pwallet->AvailableCoins (&availableCoins, nullptr , coinsFilter));
189+ for (const auto & coin : availableCoins) {
190+ if (!IsSpentOnFork (coin, forkchain)) {
191+ return coin;
192+ }
193+ }
194+ throw std::runtime_error (" Unspent coin not found" );
195+ }
196+
182197BOOST_FIXTURE_TEST_CASE (created_on_fork_tests, TestPoSChainSetup)
183198{
184199 // Let's create few more PoS blocks
@@ -354,12 +369,9 @@ BOOST_FIXTURE_TEST_CASE(created_on_fork_tests, TestPoSChainSetup)
354369 // ##############################################################################
355370
356371 // First create new coins in G
357- std::vector<COutput> availableCoins;
358- CWallet::AvailableCoinsFilter coinsFilter;
359- coinsFilter.nMaximumCount = 3 ;
360- coinsFilter.minDepth = 20 ;
361- BOOST_CHECK (pwalletMain->AvailableCoins (&availableCoins, nullptr , coinsFilter));
362- COutput input = availableCoins.at (0 );
372+ // select an input that is not already spent in D3 or E3 (since we want to spend it also in G3)
373+ const COutput& input = GetUnspentCoin (pwalletMain.get (), {pblockD3, pblockE3});
374+
363375 coinControl.UnSelectAll ();
364376 coinControl.Select (COutPoint (input.tx ->GetHash (), input.i ), input.Value ());
365377 coinControl.fAllowOtherInputs = false ;
0 commit comments