From c31a34fbcb719e2ee719588e3349c706dfed0c36 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Wed, 30 Sep 2020 17:57:06 -0600 Subject: [PATCH] Include post balance information for rewards (#12598) * Include post balance information for rewards * Add post-balance to stored Reward struct * Handle extended Reward in bigtable Co-authored-by: Michael Vines --- core/src/rewards_recorder_service.rs | 10 +++--- runtime/src/bank.rs | 33 ++++++++++++++--- .../proto/solana.bigtable.confirmed_block.rs | 2 ++ storage-bigtable/src/confirmed_block.proto | 1 + storage-bigtable/src/convert.rs | 2 ++ storage-bigtable/src/lib.rs | 36 ++++++++++++++++--- transaction-status/src/lib.rs | 3 ++ 7 files changed, 74 insertions(+), 13 deletions(-) diff --git a/core/src/rewards_recorder_service.rs b/core/src/rewards_recorder_service.rs index 18fdbcc54..e5deb0187 100644 --- a/core/src/rewards_recorder_service.rs +++ b/core/src/rewards_recorder_service.rs @@ -1,5 +1,6 @@ use crossbeam_channel::{Receiver, RecvTimeoutError, Sender}; use solana_ledger::blockstore::Blockstore; +use solana_runtime::bank::RewardInfo; use solana_sdk::{clock::Slot, pubkey::Pubkey}; use solana_transaction_status::Reward; use std::{ @@ -11,8 +12,8 @@ use std::{ time::Duration, }; -pub type RewardsRecorderReceiver = Receiver<(Slot, Vec<(Pubkey, i64)>)>; -pub type RewardsRecorderSender = Sender<(Slot, Vec<(Pubkey, i64)>)>; +pub type RewardsRecorderReceiver = Receiver<(Slot, Vec<(Pubkey, RewardInfo)>)>; +pub type RewardsRecorderSender = Sender<(Slot, Vec<(Pubkey, RewardInfo)>)>; pub struct RewardsRecorderService { thread_hdl: JoinHandle<()>, @@ -49,9 +50,10 @@ impl RewardsRecorderService { let (slot, rewards) = rewards_receiver.recv_timeout(Duration::from_secs(1))?; let rpc_rewards = rewards .into_iter() - .map(|(pubkey, lamports)| Reward { + .map(|(pubkey, reward_info)| Reward { pubkey: pubkey.to_string(), - lamports, + lamports: reward_info.lamports, + post_balance: reward_info.post_balance, }) .collect(); diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 15167253b..b7ce5481c 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -477,6 +477,12 @@ pub(crate) struct BankFieldsToSerialize<'a> { pub(crate) is_delta: bool, } +#[derive(Debug, PartialEq, Serialize, Deserialize, AbiExample, Default, Clone, Copy)] +pub struct RewardInfo { + pub lamports: i64, // Reward amount + pub post_balance: u64, // Account balance in lamports after `lamports` was applied +} + /// Manager for the state of all accounts and programs after processing its entries. /// AbiExample is needed even without Serialize/Deserialize; actual (de-)serialization /// are implemented elsewhere for versioning @@ -592,7 +598,7 @@ pub struct Bank { pub last_vote_sync: AtomicU64, /// Rewards that were paid out immediately after this bank was created - pub rewards: Option>, + pub rewards: Option>, pub skip_drop: AtomicBool, @@ -1142,7 +1148,13 @@ impl Bank { if let Some(rewards) = self.rewards.as_ref() { assert_eq!( validator_rewards_paid, - u64::try_from(rewards.iter().map(|(_pubkey, reward)| reward).sum::()).unwrap() + u64::try_from( + rewards + .iter() + .map(|(_pubkey, reward_info)| reward_info.lamports) + .sum::() + ) + .unwrap() ); } @@ -1247,11 +1259,19 @@ impl Bank { vote_account_changed = true; if voters_reward > 0 { - *rewards.entry(*vote_pubkey).or_insert(0i64) += voters_reward as i64; + let reward_info = rewards + .entry(*vote_pubkey) + .or_insert_with(RewardInfo::default); + reward_info.lamports += voters_reward as i64; + reward_info.post_balance = vote_account.lamports; } if stakers_reward > 0 { - *rewards.entry(*stake_pubkey).or_insert(0i64) += stakers_reward as i64; + let reward_info = rewards + .entry(*stake_pubkey) + .or_insert_with(RewardInfo::default); + reward_info.lamports += stakers_reward as i64; + reward_info.post_balance = stake_account.lamports; } } else { debug!( @@ -5513,7 +5533,10 @@ mod tests { bank1.rewards, Some(vec![( stake_id, - (rewards.validator_point_value * validator_points as f64) as i64 + RewardInfo { + lamports: (rewards.validator_point_value * validator_points as f64) as i64, + post_balance: bank1.get_balance(&stake_id), + } )]) ); bank1.freeze(); diff --git a/storage-bigtable/proto/solana.bigtable.confirmed_block.rs b/storage-bigtable/proto/solana.bigtable.confirmed_block.rs index f49b1a7a4..699a54111 100644 --- a/storage-bigtable/proto/solana.bigtable.confirmed_block.rs +++ b/storage-bigtable/proto/solana.bigtable.confirmed_block.rs @@ -87,6 +87,8 @@ pub struct Reward { pub pubkey: std::string::String, #[prost(int64, tag = "2")] pub lamports: i64, + #[prost(uint64, tag = "3")] + pub post_balance: u64, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct UnixTimestamp { diff --git a/storage-bigtable/src/confirmed_block.proto b/storage-bigtable/src/confirmed_block.proto index 762dd1faf..6ee9ed49b 100644 --- a/storage-bigtable/src/confirmed_block.proto +++ b/storage-bigtable/src/confirmed_block.proto @@ -60,6 +60,7 @@ message CompiledInstruction { message Reward { string pubkey = 1; int64 lamports = 2; + uint64 post_balance = 3; } message UnixTimestamp { diff --git a/storage-bigtable/src/convert.rs b/storage-bigtable/src/convert.rs index cafe71552..fe5c4ecce 100644 --- a/storage-bigtable/src/convert.rs +++ b/storage-bigtable/src/convert.rs @@ -23,6 +23,7 @@ impl From for generated::Reward { Self { pubkey: reward.pubkey, lamports: reward.lamports, + post_balance: reward.post_balance, } } } @@ -32,6 +33,7 @@ impl From for Reward { Self { pubkey: reward.pubkey, lamports: reward.lamports, + post_balance: reward.post_balance, } } } diff --git a/storage-bigtable/src/lib.rs b/storage-bigtable/src/lib.rs index 7c8761be3..f1a3445ab 100644 --- a/storage-bigtable/src/lib.rs +++ b/storage-bigtable/src/lib.rs @@ -8,7 +8,7 @@ use solana_sdk::{ transaction::{Transaction, TransactionError}, }; use solana_transaction_status::{ - ConfirmedBlock, ConfirmedTransaction, ConfirmedTransactionStatusWithSignature, Rewards, + ConfirmedBlock, ConfirmedTransaction, ConfirmedTransactionStatusWithSignature, Reward, TransactionStatus, TransactionStatusMeta, TransactionWithStatusMeta, }; use std::{collections::HashMap, convert::TryInto}; @@ -86,7 +86,7 @@ struct StoredConfirmedBlock { blockhash: String, parent_slot: Slot, transactions: Vec, - rewards: Rewards, + rewards: StoredConfirmedBlockRewards, block_time: Option, } @@ -106,7 +106,7 @@ impl From for StoredConfirmedBlock { blockhash, parent_slot, transactions: transactions.into_iter().map(|tx| tx.into()).collect(), - rewards, + rewards: rewards.into_iter().map(|reward| reward.into()).collect(), block_time, } } @@ -128,7 +128,7 @@ impl From for ConfirmedBlock { blockhash, parent_slot, transactions: transactions.into_iter().map(|tx| tx.into()).collect(), - rewards, + rewards: rewards.into_iter().map(|reward| reward.into()).collect(), block_time, } } @@ -206,6 +206,34 @@ impl From for StoredConfirmedBlockTransactionStatusMeta { } } +type StoredConfirmedBlockRewards = Vec; + +#[derive(Serialize, Deserialize)] +struct StoredConfirmedBlockReward { + pubkey: String, + lamports: i64, +} + +impl From for Reward { + fn from(value: StoredConfirmedBlockReward) -> Self { + let StoredConfirmedBlockReward { pubkey, lamports } = value; + Self { + pubkey, + lamports, + post_balance: 0, + } + } +} + +impl From for StoredConfirmedBlockReward { + fn from(value: Reward) -> Self { + let Reward { + pubkey, lamports, .. + } = value; + Self { pubkey, lamports } + } +} + // A serialized `TransactionInfo` is stored in the `tx` table #[derive(Serialize, Deserialize)] struct TransactionInfo { diff --git a/transaction-status/src/lib.rs b/transaction-status/src/lib.rs index c124c0276..b1aaff157 100644 --- a/transaction-status/src/lib.rs +++ b/transaction-status/src/lib.rs @@ -228,9 +228,12 @@ pub struct ConfirmedTransactionStatusWithSignature { } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct Reward { pub pubkey: String, pub lamports: i64, + #[serde(deserialize_with = "default_on_eof")] + pub post_balance: u64, // Account balance in lamports after `lamports` was applied } pub type Rewards = Vec;