diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1786,10 +1786,29 @@ return DISCONNECT_FAILED; } - // Undo transactions in reverse order. - size_t i = block.vtx.size(); - while (i-- > 0) { + // First, restore inputs. + for (size_t i = 1; i < block.vtx.size(); i++) { const CTransaction &tx = *(block.vtx[i]); + const CTxUndo &txundo = blockUndo.vtxundo[i - 1]; + if (txundo.vprevout.size() != tx.vin.size()) { + error("DisconnectBlock(): transaction and undo data inconsistent"); + return DISCONNECT_FAILED; + } + + for (size_t j = 0; j < tx.vin.size(); j++) { + const COutPoint &out = tx.vin[j].prevout; + const Coin &undo = txundo.vprevout[j]; + DisconnectResult res = UndoCoinSpend(undo, view, out); + if (res == DISCONNECT_FAILED) { + return DISCONNECT_FAILED; + } + fClean = fClean && res != DISCONNECT_UNCLEAN; + } + } + + // Second, revert created outputs. + for (const auto &ptx : block.vtx) { + const CTransaction &tx = *ptx; uint256 txid = tx.GetId(); // Check that all outputs are available and match the outputs in the @@ -1807,28 +1826,6 @@ fClean = false; } } - - // Restore inputs. - if (i < 1) { - // Skip the coinbase. - continue; - } - - const CTxUndo &txundo = blockUndo.vtxundo[i - 1]; - if (txundo.vprevout.size() != tx.vin.size()) { - error("DisconnectBlock(): transaction and undo data inconsistent"); - return DISCONNECT_FAILED; - } - - for (size_t j = tx.vin.size(); j-- > 0;) { - const COutPoint &out = tx.vin[j].prevout; - const Coin &undo = txundo.vprevout[j]; - DisconnectResult res = UndoCoinSpend(undo, view, out); - if (res == DISCONNECT_FAILED) { - return DISCONNECT_FAILED; - } - fClean = fClean && res != DISCONNECT_UNCLEAN; - } } // Move best block pointer to previous block. diff --git a/test/functional/abc-transaction-ordering.py b/test/functional/abc-transaction-ordering.py --- a/test/functional/abc-transaction-ordering.py +++ b/test/functional/abc-transaction-ordering.py @@ -244,6 +244,10 @@ out_of_order_block(4445, out[16]) yield accepted() + oooblockhash = node.getbestblockhash() + node.invalidateblock(oooblockhash) + assert(node.getbestblockhash() != oooblockhash) + if __name__ == '__main__': TransactionOrderingTest().main()