Skip to content

Commit af08ba9

Browse files
Evgeny Kuzyakovnearprotocol-bulldozer[bot]
Evgeny Kuzyakov
authored andcommitted
Move rewards to runtime (#1497)
* Move validator rewards to runtime * Merge branch 'staging' of github.com:nearprotocol/nearcore into move-rewards-to-runtime * Merge branch 'staging' of github.com:nearprotocol/nearcore into move-rewards-to-runtime * Update runtime/runtime/src/lib.rs Co-Authored-By: Maksym Zavershynskyi <35039879+nearmax@users.noreply.github.com> * Merge branch 'staging' of github.com:nearprotocol/nearcore into move-rewards-to-runtime * Merge branch 'move-rewards-to-runtime' of github.com:nearprotocol/nearcore into move-rewards-to-runtime * Merge branch 'staging' into move-rewards-to-runtime * Merge refs/heads/staging into move-rewards-to-runtime
1 parent 1e78985 commit af08ba9

File tree

8 files changed

+501
-362
lines changed

8 files changed

+501
-362
lines changed

core/primitives/src/errors.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ impl Display for InvalidAccessKeyError {
170170
#[derive(BorshSerialize, BorshDeserialize, Debug, Clone, PartialEq, Eq)]
171171
pub struct BalanceMismatchError {
172172
// Input balances
173+
pub incoming_validator_rewards: Balance,
173174
pub initial_accounts_balance: Balance,
174175
pub incoming_receipts_balance: Balance,
175176
pub initial_postponed_receipts_balance: Balance,
@@ -186,7 +187,8 @@ impl Display for BalanceMismatchError {
186187
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
187188
// Using saturating add to avoid overflow in display
188189
let initial_balance = self
189-
.initial_accounts_balance
190+
.incoming_validator_rewards
191+
.saturating_add(self.initial_accounts_balance)
190192
.saturating_add(self.incoming_receipts_balance)
191193
.saturating_add(self.initial_postponed_receipts_balance);
192194
let final_balance = self
@@ -200,6 +202,7 @@ impl Display for BalanceMismatchError {
200202
f,
201203
"Balance Mismatch Error. The input balance {} doesn't match output balance {}\n\
202204
Inputs:\n\
205+
\tIncoming validator rewards sum: {}\n\
203206
\tInitial accounts balance sum: {}\n\
204207
\tIncoming receipts balance sum: {}\n\
205208
\tInitial postponed receipts balance sum: {}\n\
@@ -212,6 +215,7 @@ impl Display for BalanceMismatchError {
212215
\tTotal balance burnt: {}",
213216
initial_balance,
214217
final_balance,
218+
self.incoming_validator_rewards,
215219
self.initial_accounts_balance,
216220
self.incoming_receipts_balance,
217221
self.initial_postponed_receipts_balance,

core/store/src/trie/update.rs

-14
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@ use crate::trie::TrieChanges;
1212
use super::{Trie, TrieIterator};
1313
use crate::StorageError;
1414

15-
// TODO(#1481): Remove clone after Runtime bug is fixed.
1615
/// Provides a way to access Storage and record changes with future commit.
17-
#[derive(Clone)]
1816
pub struct TrieUpdate {
1917
pub trie: Arc<Trie>,
2018
root: MerkleHash,
@@ -276,18 +274,6 @@ mod tests {
276274

277275
use super::*;
278276

279-
// TODO(#1481): Remove clone after Runtime bug is fixed.
280-
#[test]
281-
fn trie_clone() {
282-
let trie = create_trie();
283-
let root = MerkleHash::default();
284-
let mut trie_update = TrieUpdate::new(trie.clone(), root);
285-
trie_update.set(b"dog".to_vec(), DBValue::from_slice(b"puppy"));
286-
let trie_cloned = trie_update.clone();
287-
trie_update.set(b"dog".to_vec(), DBValue::from_slice(b"batman"));
288-
assert_eq!(trie_cloned.get(b"dog"), Ok(Some(DBValue::from_slice(b"puppy"))));
289-
}
290-
291277
#[test]
292278
fn trie() {
293279
let trie = create_trie();

near/src/runtime.rs

+41-86
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use std::cmp::max;
21
use std::collections::{HashMap, HashSet};
32
use std::convert::{TryFrom, TryInto};
43
use std::fs::File;
@@ -30,12 +29,11 @@ use near_primitives::views::{
3029
AccessKeyInfoView, CallResult, QueryError, QueryResponse, ViewStateResult,
3130
};
3231
use near_store::{
33-
get_access_key_raw, get_account, set_account, StorageError, Store, StoreUpdate, Trie,
34-
TrieUpdate, WrappedTrieChanges, COL_STATE,
32+
get_access_key_raw, Store, StoreUpdate, Trie, TrieUpdate, WrappedTrieChanges, COL_STATE,
3533
};
3634
use node_runtime::adapter::ViewRuntimeAdapter;
3735
use node_runtime::state_viewer::TrieViewer;
38-
use node_runtime::{ApplyState, Runtime, StateRecord};
36+
use node_runtime::{ApplyState, Runtime, StateRecord, ValidatorAccountsUpdate};
3937

4038
use crate::config::GenesisConfig;
4139
use crate::shard_tracker::{account_id_to_shard_id, ShardTracker};
@@ -126,68 +124,6 @@ impl NightshadeRuntime {
126124
}
127125
}
128126

129-
/// Iterates over validator accounts in the given shard and updates their accounts to return stake
130-
/// and allocate rewards.
131-
fn update_validator_accounts(
132-
&self,
133-
shard_id: ShardId,
134-
block_hash: &CryptoHash,
135-
last_validator_proposals: &[ValidatorStake],
136-
state_update: &mut TrieUpdate,
137-
) -> Result<(), Box<dyn std::error::Error>> {
138-
let mut epoch_manager = self.epoch_manager.write().expect(POISONED_LOCK_ERR);
139-
let (stake_info, validator_reward) = epoch_manager.compute_stake_return_info(block_hash)?;
140-
let account_to_stake =
141-
last_validator_proposals.iter().fold(HashMap::new(), |mut acc, v| {
142-
acc.insert(v.account_id.clone(), v.amount);
143-
acc
144-
});
145-
146-
for (account_id, max_of_stakes) in stake_info {
147-
if self.account_id_to_shard_id(&account_id) == shard_id {
148-
let account: Option<Account> = get_account(state_update, &account_id)?;
149-
if let Some(mut account) = account {
150-
if let Some(reward) = validator_reward.get(&account_id) {
151-
debug!(target: "runtime", "account {} adding reward {} to stake {}", account_id, reward, account.locked);
152-
account.locked += *reward;
153-
}
154-
155-
debug!(target: "runtime",
156-
"account {} stake {} max_of_stakes: {}",
157-
account_id, account.locked, max_of_stakes
158-
);
159-
assert!(
160-
account.locked >= max_of_stakes,
161-
"FATAL: staking invariant does not hold. Account stake {} is less than maximum of stakes {} in the past three epochs",
162-
account.locked,
163-
max_of_stakes
164-
);
165-
let last_stake = *account_to_stake.get(&account_id).unwrap_or(&0);
166-
let return_stake = account.locked - max(max_of_stakes, last_stake);
167-
debug!(target: "runtime", "account {} return stake {}", account_id, return_stake);
168-
account.locked -= return_stake;
169-
account.amount += return_stake;
170-
171-
set_account(state_update, &account_id, &account);
172-
}
173-
}
174-
}
175-
if self.account_id_to_shard_id(&self.genesis_config.protocol_treasury_account) == shard_id {
176-
let mut protocol_treasury_account =
177-
get_account(state_update, &self.genesis_config.protocol_treasury_account)?.unwrap();
178-
protocol_treasury_account.amount +=
179-
*validator_reward.get(&self.genesis_config.protocol_treasury_account).unwrap();
180-
set_account(
181-
state_update,
182-
&self.genesis_config.protocol_treasury_account,
183-
&protocol_treasury_account,
184-
);
185-
}
186-
state_update.commit();
187-
188-
Ok(())
189-
}
190-
191127
fn genesis_state_from_dump(&self) -> (StoreUpdate, Vec<StateRoot>) {
192128
let store_update = self.store.store_update();
193129
let mut state_file = self.home_dir.clone();
@@ -603,33 +539,45 @@ impl RuntimeAdapter for NightshadeRuntime {
603539
} else {
604540
self.trie.clone()
605541
};
606-
let mut state_update = TrieUpdate::new(trie.clone(), state_root.hash);
607-
let should_update_account = {
542+
let validator_accounts_update = {
608543
let mut epoch_manager = self.epoch_manager.write().expect(POISONED_LOCK_ERR);
609544
debug!(target: "runtime",
610545
"block index: {}, is next_block_epoch_start {}",
611546
block_index,
612547
epoch_manager.is_next_block_epoch_start(prev_block_hash).unwrap()
613548
);
614-
epoch_manager.is_next_block_epoch_start(prev_block_hash)?
549+
if epoch_manager.is_next_block_epoch_start(prev_block_hash)? {
550+
let (stake_info, validator_reward) =
551+
epoch_manager.compute_stake_return_info(prev_block_hash)?;
552+
let stake_info = stake_info
553+
.into_iter()
554+
.filter(|(account_id, _)| self.account_id_to_shard_id(account_id) == shard_id)
555+
.collect();
556+
let validator_rewards = validator_reward
557+
.into_iter()
558+
.filter(|(account_id, _)| self.account_id_to_shard_id(account_id) == shard_id)
559+
.collect();
560+
let last_proposals = last_validator_proposals
561+
.iter()
562+
.filter(|v| self.account_id_to_shard_id(&v.account_id) == shard_id)
563+
.fold(HashMap::new(), |mut acc, v| {
564+
acc.insert(v.account_id.clone(), v.amount);
565+
acc
566+
});
567+
Some(ValidatorAccountsUpdate {
568+
stake_info,
569+
validator_rewards,
570+
last_proposals,
571+
protocol_treasury_account_id: Some(
572+
self.genesis_config.protocol_treasury_account.clone(),
573+
)
574+
.filter(|account_id| self.account_id_to_shard_id(account_id) == shard_id),
575+
})
576+
} else {
577+
None
578+
}
615579
};
616580

617-
// If we are starting to apply 1st block in the new epoch.
618-
if should_update_account {
619-
self.update_validator_accounts(
620-
shard_id,
621-
prev_block_hash,
622-
last_validator_proposals,
623-
&mut state_update,
624-
)
625-
.map_err(|e| {
626-
if let Some(e) = e.downcast_ref::<StorageError>() {
627-
panic!(e.to_string())
628-
}
629-
Error::from(ErrorKind::ValidatorError(e.to_string()))
630-
})?;
631-
}
632-
633581
let apply_state = ApplyState {
634582
block_index,
635583
epoch_length: self.genesis_config.epoch_length,
@@ -639,7 +587,14 @@ impl RuntimeAdapter for NightshadeRuntime {
639587

640588
let apply_result = self
641589
.runtime
642-
.apply(state_update, &apply_state, &receipts, &transactions)
590+
.apply(
591+
trie.clone(),
592+
state_root.hash,
593+
&validator_accounts_update,
594+
&apply_state,
595+
&receipts,
596+
&transactions,
597+
)
643598
.map_err(|e| match e {
644599
RuntimeError::InvalidTxError(_) => ErrorKind::InvalidTransactions,
645600
RuntimeError::BalanceMismatch(e) => panic!("{}", e),

runtime/runtime-params-estimator/src/testbed.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use near::get_store_path;
33
use near_primitives::receipt::Receipt;
44
use near_primitives::transaction::{ExecutionStatus, SignedTransaction};
55
use near_primitives::types::MerkleHash;
6-
use near_store::{create_store, Trie, TrieUpdate, COL_STATE};
6+
use near_store::{create_store, Trie, COL_STATE};
77
use node_runtime::config::RuntimeConfig;
88
use node_runtime::{ApplyState, Runtime};
99
use std::fs::File;
@@ -64,10 +64,16 @@ impl RuntimeTestbed {
6464
}
6565

6666
pub fn process_block(&mut self, transactions: &[SignedTransaction], allow_failures: bool) {
67-
let state_update = TrieUpdate::new(self.trie.clone(), self.root);
6867
let apply_result = self
6968
.runtime
70-
.apply(state_update, &self.apply_state, &self.prev_receipts, transactions)
69+
.apply(
70+
self.trie.clone(),
71+
self.root,
72+
&None,
73+
&self.apply_state,
74+
&self.prev_receipts,
75+
transactions,
76+
)
7177
.unwrap();
7278

7379
let (store_update, root) = apply_result.trie_changes.into(self.trie.clone()).unwrap();

0 commit comments

Comments
 (0)