Skip to content

Commit

Permalink
RPC: rewards, return error if epoch_boundary_block is a lie (#2758)
Browse files Browse the repository at this point in the history
* Return error if epoch_boundary_block is not actually the epoch boundary block

* Update rpc-client-api/src/custom_error.rs

Co-authored-by: Trent Nelson <[email protected]>

---------

Co-authored-by: Trent Nelson <[email protected]>
(cherry picked from commit 9a4b094)

# Conflicts:
#	rpc-client-api/src/custom_error.rs
#	rpc/src/rpc.rs
  • Loading branch information
CriesofCarrots authored and mergify[bot] committed Aug 28, 2024
1 parent 11e166f commit 79028ec
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 0 deletions.
35 changes: 35 additions & 0 deletions rpc-client-api/src/custom_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ pub const JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_LEN_MISMATCH: i64 = -32013
pub const JSON_RPC_SERVER_ERROR_BLOCK_STATUS_NOT_AVAILABLE_YET: i64 = -32014;
pub const JSON_RPC_SERVER_ERROR_UNSUPPORTED_TRANSACTION_VERSION: i64 = -32015;
pub const JSON_RPC_SERVER_ERROR_MIN_CONTEXT_SLOT_NOT_REACHED: i64 = -32016;
<<<<<<< HEAD
=======
pub const JSON_RPC_SERVER_ERROR_EPOCH_REWARDS_PERIOD_ACTIVE: i64 = -32017;
pub const JSON_RPC_SERVER_ERROR_SLOT_NOT_EPOCH_BOUNDARY: i64 = -32018;
>>>>>>> 9a4b094ded (RPC: rewards, return error if epoch_boundary_block is a lie (#2758))

#[derive(Error, Debug)]
pub enum RpcCustomError {
Expand Down Expand Up @@ -65,6 +70,17 @@ pub enum RpcCustomError {
UnsupportedTransactionVersion(u8),
#[error("MinContextSlotNotReached")]
MinContextSlotNotReached { context_slot: Slot },
<<<<<<< HEAD
=======
#[error("EpochRewardsPeriodActive")]
EpochRewardsPeriodActive {
slot: Slot,
current_block_height: u64,
rewards_complete_block_height: u64,
},
#[error("SlotNotEpochBoundary")]
SlotNotEpochBoundary { slot: Slot },
>>>>>>> 9a4b094ded (RPC: rewards, return error if epoch_boundary_block is a lie (#2758))
}

#[derive(Debug, Serialize, Deserialize)]
Expand Down Expand Up @@ -206,6 +222,25 @@ impl From<RpcCustomError> for Error {
context_slot,
})),
},
<<<<<<< HEAD
=======
RpcCustomError::EpochRewardsPeriodActive { slot, current_block_height, rewards_complete_block_height } => Self {
code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_EPOCH_REWARDS_PERIOD_ACTIVE),
message: format!("Epoch rewards period still active at slot {slot}"),
data: Some(serde_json::json!(EpochRewardsPeriodActiveErrorData {
current_block_height,
rewards_complete_block_height,
})),
},
RpcCustomError::SlotNotEpochBoundary { slot } => Self {
code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_SLOT_NOT_EPOCH_BOUNDARY),
message: format!(
"Rewards cannot be found because slot {slot} is not the epoch boundary. This \
may be due to gap in the queried node's local ledger or long-term storage"
),
data: None,
},
>>>>>>> 9a4b094ded (RPC: rewards, return error if epoch_boundary_block is a lie (#2758))
}
}
}
32 changes: 32 additions & 0 deletions rpc/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,10 +575,42 @@ impl JsonRpcRequestProcessor {
.into());
};

<<<<<<< HEAD
let addresses: Vec<String> = addresses
.into_iter()
.map(|pubkey| pubkey.to_string())
.collect();
=======
// If there is a gap in blockstore or long-term historical storage that
// includes the epoch boundary, the `get_blocks_with_limit()` call above
// will return the slot of the block at the end of that gap, not a
// legitimate epoch-boundary block. Therefore, verify that the parent of
// `epoch_boundary_block` occurred before the `first_slot_in_epoch`. If
// it didn't, return an error; it will be impossible to locate
// rewards properly.
if epoch_boundary_block.parent_slot >= first_slot_in_epoch {
return Err(RpcCustomError::SlotNotEpochBoundary {
slot: first_confirmed_block_in_epoch,
}
.into());
}

// Collect rewards from first block in the epoch if partitioned epoch
// rewards not enabled, or address is a vote account
let mut reward_map: HashMap<String, (Reward, Slot)> = {
let addresses: Vec<String> =
addresses.iter().map(|pubkey| pubkey.to_string()).collect();
Self::filter_map_rewards(
&epoch_boundary_block.rewards,
first_confirmed_block_in_epoch,
&addresses,
&|reward_type| -> bool {
reward_type == RewardType::Voting
|| (!partitioned_epoch_reward_enabled && reward_type == RewardType::Staking)
},
)
};
>>>>>>> 9a4b094ded (RPC: rewards, return error if epoch_boundary_block is a lie (#2758))

let reward_hash: HashMap<String, Reward> = first_confirmed_block
.rewards
Expand Down

0 comments on commit 79028ec

Please sign in to comment.