47
47
48
48
#include < future>
49
49
#include < sstream>
50
+ #include < string>
50
51
51
52
#include < boost/algorithm/string/replace.hpp>
52
53
#include < boost/thread.hpp>
@@ -193,8 +194,8 @@ class CChainState {
193
194
void UnloadBlockIndex ();
194
195
195
196
private:
196
- bool ActivateBestChainStep (CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool & fInvalidFound , ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
197
- bool ConnectTip (CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
197
+ bool ActivateBestChainStep (CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool & fInvalidFound , ConnectTrace& connectTrace, bool & fStall ) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
198
+ bool ConnectTip (CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool, bool & fStall ) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
198
199
199
200
CBlockIndex* AddToBlockIndex (const CBlockHeader& block) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
200
201
/* * Create a new block index entry for a given block hash */
@@ -1936,6 +1937,35 @@ static int64_t nTimeCallbacks = 0;
1936
1937
static int64_t nTimeTotal = 0 ;
1937
1938
static int64_t nBlocksTotal = 0 ;
1938
1939
1940
+ bool CheckPeginRipeness (const CBlock& block, const std::vector<std::pair<CScript, CScript>>& fedpegscripts) {
1941
+ for (unsigned int i = 0 ; i < block.vtx .size (); i++) {
1942
+ const CTransaction &tx = *(block.vtx [i]);
1943
+
1944
+ if (!tx.IsCoinBase ()) {
1945
+ for (unsigned int i = 0 ; i < tx.vin .size (); ++i) {
1946
+ if (tx.vin [i].m_is_pegin ) {
1947
+ std::string err;
1948
+ // IsValidPeginWitness technically checks more than just "ripeness". As a result,
1949
+ // if we get a validly-signed block which contains an ill-formed pegin witness,
1950
+ // this test will fail, and it will be treated as "unripe" rather than invalid,
1951
+ // resulting in a stall rather than rejecting the block. This is reasonable, because
1952
+ // in this case (invalid block that is validly-signed by the federation), something
1953
+ // very strange has happened anyway.
1954
+ if ((tx.witness .vtxinwit .size () <= i) || !IsValidPeginWitness (tx.witness .vtxinwit [i].m_pegin_witness , fedpegscripts, tx.vin [i].prevout , err, true )) {
1955
+ // This is not the ideal way to check this, but we already do this in one other place.
1956
+ if (!strcmp (err.c_str (), " Needs more confirmations." )) {
1957
+ return false ; // Pegins not ripe.
1958
+ } else {
1959
+ return true ; // Some other failure; details later.
1960
+ }
1961
+ }
1962
+ }
1963
+ }
1964
+ }
1965
+ }
1966
+ return true ;
1967
+ }
1968
+
1939
1969
/* * Apply the effects of this block (with given index) on the UTXO set represented by coins.
1940
1970
* Validity checks that depend on the UTXO set are also done; ConnectBlock()
1941
1971
* can fail if those validity checks fail (among other reasons). */
@@ -2601,7 +2631,7 @@ class ConnectTrace {
2601
2631
*
2602
2632
* The block is added to connectTrace if connection succeeds.
2603
2633
*/
2604
- bool CChainState::ConnectTip (CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool)
2634
+ bool CChainState::ConnectTip (CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool, bool & fStall )
2605
2635
{
2606
2636
assert (pindexNew->pprev == chainActive.Tip ());
2607
2637
// Read block from disk.
@@ -2616,6 +2646,14 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp
2616
2646
pthisBlock = pblock;
2617
2647
}
2618
2648
const CBlock& blockConnecting = *pthisBlock;
2649
+
2650
+ const auto & fedpegscripts = GetValidFedpegScripts (pindexNew, chainparams.GetConsensus (), false /* nextblock_validation */ );
2651
+ if (!CheckPeginRipeness (blockConnecting, fedpegscripts)) {
2652
+ LogPrintf (" STALLING further progress in ConnectTip while waiting for parent chain daemon to catch up! Chain will not grow until this is remedied!\n " );
2653
+ fStall = true ;
2654
+ return true ;
2655
+ }
2656
+
2619
2657
// Apply the block atomically to the chain state.
2620
2658
int64_t nTime2 = GetTimeMicros (); nTimeReadFromDisk += nTime2 - nTime1;
2621
2659
int64_t nTime3;
@@ -2632,29 +2670,6 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp
2632
2670
if (!rv) {
2633
2671
if (state.IsInvalid ()) {
2634
2672
InvalidBlockFound (pindexNew, state);
2635
-
2636
- // ELEMENTS:
2637
- // Possibly result of RPC to mainchain bitcoind failure
2638
- // or unseen Bitcoin blocks.
2639
- // These blocks are later re-evaluated at an interval
2640
- // set by `-recheckpeginblockinterval`.
2641
- if (state.GetRejectCode () == REJECT_PEGIN) {
2642
- // Write queue of invalid blocks that
2643
- // must be cleared to continue operation
2644
- std::vector<uint256> vinvalidBlocks;
2645
- pblocktree->ReadInvalidBlockQueue (vinvalidBlocks);
2646
- bool blockAlreadyInvalid = false ;
2647
- for (uint256& hash : vinvalidBlocks) {
2648
- if (hash == blockConnecting.GetHash ()) {
2649
- blockAlreadyInvalid = true ;
2650
- break ;
2651
- }
2652
- }
2653
- if (!blockAlreadyInvalid) {
2654
- vinvalidBlocks.push_back (blockConnecting.GetHash ());
2655
- pblocktree->WriteInvalidBlockQueue (vinvalidBlocks);
2656
- }
2657
- }
2658
2673
}
2659
2674
return error (" %s: ConnectBlock %s failed, %s" , __func__, pindexNew->GetBlockHash ().ToString (), FormatStateMessage (state));
2660
2675
}
@@ -2762,7 +2777,7 @@ void CChainState::PruneBlockIndexCandidates() {
2762
2777
* Try to make some progress towards making pindexMostWork the active block.
2763
2778
* pblock is either nullptr or a pointer to a CBlock corresponding to pindexMostWork.
2764
2779
*/
2765
- bool CChainState::ActivateBestChainStep (CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool & fInvalidFound , ConnectTrace& connectTrace)
2780
+ bool CChainState::ActivateBestChainStep (CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool & fInvalidFound , ConnectTrace& connectTrace, bool & fStall )
2766
2781
{
2767
2782
AssertLockHeld (cs_main);
2768
2783
@@ -2801,7 +2816,7 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar
2801
2816
2802
2817
// Connect new blocks.
2803
2818
for (CBlockIndex *pindexConnect : reverse_iterate (vpindexToConnect)) {
2804
- if (!ConnectTip (state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : std::shared_ptr<const CBlock>(), connectTrace, disconnectpool)) {
2819
+ if (!ConnectTip (state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : std::shared_ptr<const CBlock>(), connectTrace, disconnectpool, fStall )) {
2805
2820
if (state.IsInvalid ()) {
2806
2821
// The block violates a consensus rule.
2807
2822
if (!state.CorruptionPossible ()) {
@@ -2819,6 +2834,12 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar
2819
2834
return false ;
2820
2835
}
2821
2836
} else {
2837
+ if (fStall ) {
2838
+ // We didn't make progress because the parent chain is not
2839
+ // synced enough to check pegins. Try again later.
2840
+ fContinue = false ;
2841
+ break ;
2842
+ }
2822
2843
PruneBlockIndexCandidates ();
2823
2844
if (!pindexOldTip || chainActive.Tip ()->nChainWork > pindexOldTip->nChainWork ) {
2824
2845
// We're in a better position than we were. Return temporarily to release the lock.
@@ -2899,6 +2920,8 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
2899
2920
CBlockIndex *pindexMostWork = nullptr ;
2900
2921
CBlockIndex *pindexNewTip = nullptr ;
2901
2922
int nStopAtHeight = gArgs .GetArg (" -stopatheight" , DEFAULT_STOPATHEIGHT);
2923
+ bool fStall = false ;
2924
+
2902
2925
do {
2903
2926
boost::this_thread::interruption_point ();
2904
2927
@@ -2930,7 +2953,7 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
2930
2953
2931
2954
bool fInvalidFound = false ;
2932
2955
std::shared_ptr<const CBlock> nullBlockPtr;
2933
- if (!ActivateBestChainStep (state, chainparams, pindexMostWork, pblock && pblock->GetHash () == pindexMostWork->GetBlockHash () ? pblock : nullBlockPtr, fInvalidFound , connectTrace))
2956
+ if (!ActivateBestChainStep (state, chainparams, pindexMostWork, pblock && pblock->GetHash () == pindexMostWork->GetBlockHash () ? pblock : nullBlockPtr, fInvalidFound , connectTrace, fStall ))
2934
2957
return false ;
2935
2958
blocks_connected = true ;
2936
2959
@@ -2944,6 +2967,11 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
2944
2967
assert (trace.pblock && trace.pindex );
2945
2968
GetMainSignals ().BlockConnected (trace.pblock , trace.pindex , trace.conflictedTxs );
2946
2969
}
2970
+
2971
+ if (fStall ) {
2972
+ // Stuck waiting for parent chain daemon, twiddle our thumbs for awhile.
2973
+ break ;
2974
+ }
2947
2975
} while (!chainActive.Tip () || (starting_tip && CBlockIndexWorkComparator ()(chainActive.Tip (), starting_tip)));
2948
2976
if (!blocks_connected) return true ;
2949
2977
@@ -2962,6 +2990,11 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
2962
2990
}
2963
2991
// When we reach this point, we switched to a new tip (stored in pindexNewTip).
2964
2992
2993
+ if (fStall ) {
2994
+ // Stuck waiting for parent chain daemon, twiddle our thumbs for awhile.
2995
+ break ;
2996
+ }
2997
+
2965
2998
if (nStopAtHeight && pindexNewTip && pindexNewTip->nHeight >= nStopAtHeight) StartShutdown ();
2966
2999
2967
3000
// We check shutdown only after giving ActivateBestChainStep a chance to run once so that we
@@ -5306,34 +5339,12 @@ class CMainCleanup
5306
5339
} instance_of_cmaincleanup;
5307
5340
5308
5341
// ELEMENTS:
5309
- /* This function has two major purposes:
5310
- * 1) Checks that the RPC connection to the parent chain node
5342
+ /* This function checks that the RPC connection to the parent chain node
5311
5343
* can be attained, and is returning back reasonable answers.
5312
- * 2) Re-evaluates a list of blocks that have been deemed "bad"
5313
- * from the perspective of peg-in witness validation. Blocks are
5314
- * added to this queue in ConnectTip based on the error code returned.
5315
5344
*/
5316
5345
bool MainchainRPCCheck (const bool init)
5317
5346
{
5318
- // First, we can clear out any blocks thatsomehow are now deemed valid
5319
- // eg reconsiderblock rpc call manually
5320
- std::vector<uint256> vblocksToReconsider;
5321
- pblocktree->ReadInvalidBlockQueue (vblocksToReconsider);
5322
- std::vector<uint256> vblocksToReconsiderAgain;
5323
- for (uint256& blockhash : vblocksToReconsider) {
5324
- LOCK (cs_main);
5325
- if (mapBlockIndex.count (blockhash)) {
5326
- CBlockIndex* pblockindex = mapBlockIndex[blockhash];
5327
- if ((pblockindex->nStatus & BLOCK_FAILED_MASK)) {
5328
- vblocksToReconsiderAgain.push_back (blockhash);
5329
- }
5330
- }
5331
- }
5332
- vblocksToReconsider = vblocksToReconsiderAgain;
5333
- vblocksToReconsiderAgain.clear ();
5334
- pblocktree->WriteInvalidBlockQueue (vblocksToReconsider);
5335
-
5336
- // Next, check for working and valid rpc
5347
+ // Check for working and valid rpc
5337
5348
if (gArgs .GetBoolArg (" -validatepegin" , Params ().GetConsensus ().has_parent_chain )) {
5338
5349
// During init try until a non-RPC_IN_WARMUP result
5339
5350
while (true ) {
@@ -5384,48 +5395,5 @@ bool MainchainRPCCheck(const bool init)
5384
5395
}
5385
5396
}
5386
5397
5387
- // Sanity startup check won't reconsider queued blocks
5388
- if (init) {
5389
- return true ;
5390
- }
5391
-
5392
- // Getting this far means we either aren't validating pegins(so let's make sure that's why
5393
- // it failed previously) or we successfully connected to bitcoind
5394
- // Time to reconsider blocks
5395
- if (vblocksToReconsider.size () > 0 ) {
5396
- CValidationState state;
5397
- for (const uint256& blockhash : vblocksToReconsider) {
5398
- {
5399
- LOCK (cs_main);
5400
- if (mapBlockIndex.count (blockhash) == 0 )
5401
- continue ;
5402
- CBlockIndex* pblockindex = mapBlockIndex[blockhash];
5403
- ResetBlockFailureFlags (pblockindex);
5404
- }
5405
- }
5406
-
5407
- // All blocks are now being reconsidered
5408
- ActivateBestChain (state, Params ());
5409
- // This simply checks for DB errors
5410
- if (!state.IsValid ()) {
5411
- // Something scary?
5412
- }
5413
-
5414
- // Now to clear out now-valid blocks
5415
- for (const uint256& blockhash : vblocksToReconsider) {
5416
- LOCK (cs_main);
5417
- if (mapBlockIndex.count (blockhash)) {
5418
- CBlockIndex* pblockindex = mapBlockIndex[blockhash];
5419
-
5420
- // Marked as invalid still, put back into queue
5421
- if ((pblockindex->nStatus & BLOCK_FAILED_MASK)) {
5422
- vblocksToReconsiderAgain.push_back (blockhash);
5423
- }
5424
- }
5425
- }
5426
-
5427
- // Write back remaining blocks
5428
- pblocktree->WriteInvalidBlockQueue (vblocksToReconsiderAgain);
5429
- }
5430
5398
return true ;
5431
5399
}
0 commit comments