stacks-network / stacks-core

The Stacks blockchain implementation
https://docs.stacks.co
GNU General Public License v3.0
3.01k stars 667 forks source link

[StackerDB] race condition when handling a request for a stale chunk #5067

Open jcnelson opened 1 month ago

jcnelson commented 1 month ago

When handling a request for a chunk that the peer does not have, it performs the following:

let chunk = match stacker_dbs.get_chunk(
    &getchunk.contract_id,
    getchunk.slot_id,
    getchunk.slot_version,
) {
    Ok(Some(chunk)) => chunk,
    Ok(None) => {
        // TODO: this is racey
        if let Ok(Some(actual_version)) =
            stacker_dbs.get_slot_version(&getchunk.contract_id, getchunk.slot_id)
        {
            // request for a stale chunk
            debug!("{:?}: NACK StackerDBGetChunk; version mismatch for requested slot {}.{} for {}. Expected {}", local_peer, getchunk.slot_id, getchunk.slot_version, &getchunk.contract_id, actual_version);
            /* ... etc. */

The call to stacker_dbs.get_chunk(...) and stacker_dbs.get_slot_version(...) need to be transactional, or combined into a single query. A straightforward fix would be to implement a function called get_chunk_or_version(...) which has the same signature as get_chunk(...), but returns the DB's version of the chunk if the given chunk version is not represented.