snarkOS
snarkOS copied to clipboard
[Bug] Prover puzzle_response, expired puzzle data was received
🐛 Bug Report
https://github.com/AleoHQ/snarkOS/blob/96476474834630270299e1380be874ef9ee339e0/node/src/prover/router.rs#L196
fn puzzle_response(&self, peer_ip: SocketAddr, epoch_challenge: EpochChallenge<N>, header: Header<N>) -> bool {
// Retrieve the epoch number.
let epoch_number = epoch_challenge.epoch_number();
// Retrieve the block height.
let block_height = header.height();
let block_height = header.height();
let timestamp = header.timestamp();
let curtimestamp = OffsetDateTime::now_utc().unix_timestamp();
let mut dtime = (N::NUM_BLOCKS_PER_EPOCH - block_height % N::NUM_BLOCKS_PER_EPOCH) * (N::BLOCK_TIME as u32);
if dtime < (N::BLOCK_TIME as u32) * 5u32 {
dtime = (N::BLOCK_TIME as u32) * 5u32
}
if block_height > 0 && curtimestamp - timestamp > dtime as i64 {
error!(
"Coinbase Puzzle is outmoded (Epoch {epoch_number}, Block {block_height}, Coinbase Target {}, Proof Target {}) ",
header.coinbase_target(),
header.proof_target()
);
return false;
}
info!(
"Coinbase Puzzle (Epoch {epoch_number}, Block {block_height}, Coinbase Target {}, Proof Target {})",
header.coinbase_target(),
header.proof_target()
);
// Save the latest epoch challenge in the node.
self.latest_epoch_challenge.write().replace(Arc::new(epoch_challenge));
// Save the latest block header in the node.
self.latest_block_header.write().replace(header);
trace!("Received 'PuzzleResponse' from '{peer_ip}' (Epoch {epoch_number}, Block {block_height})");
true
}
Using "timestamps" to determine authenticity is not very rigorous, and using RPC for expiration verification is also not a good solution. Another issue is how to ensure the authenticity of the "epoch_challenge" itself.
Your Environment
The prover node would need to keep a minimal view of the chain state to verify the puzzle - what's the current height of the network and what's the block hash of the block before current epoch. The current sync module might not be enough for this, as it can be cheated to some extent.
However, that would mean the node can just locally generate the puzzle.
Yes, this can only eliminate some epochs that have already expired, and cannot verify malicious behavior.
The puzzle could be generated directly from the limited chain state, considering you only need the epoch number and the block hash from the last block of the last epoch to construct it. To rigorously verify a block hash though, you do need the full chain (if that's what you mean).