Fixes #35172.
I am still getting familiar with the codebase, so doing easy tickets for now. Thanks for bearing with me.
What?
CCoinsViewDB::Cursor() caches the first coin key after seeking into the chainstate DB. If the first DB_COIN entry is malformed, CDBIterator::GetKey() returns false, but the cursor warmup path ignored that return value.
Because CoinEntry defaults its key marker to DB_COIN, a malformed key like just C could leave the cursor reporting Valid() == true and GetKey() == true even though the key was not decoded.
This makes the warmup path match CCoinsViewDBCursor::Next(): if the iterator is invalid or the key cannot be decoded, invalidate the cached key.
Scenario
This would require an already-corrupted or manually modified local chainstate LevelDB where the first coin key is readable by LevelDB but not decodable as a CoinEntry.
Normal node operation should not create this key shape, so this is a correctness/hardening fix rather than a common user-facing issue.
Testing
The regression test writes a single-byte C key, which enters the DB_COIN keyspace but is too short to decode as a CoinEntry. It then reopens the DB through CCoinsViewDB and checks that the returned cursor is invalid.
cmake --build build --target test_bitcoin -j8
build/bin/test_bitcoin --run_test=coins_tests_dbbase/malformed_first_coin_key_cursor_invalid
build/bin/test_bitcoin --run_test=coins_tests_dbbase