Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NEP-491] Non-refundable storage #9600

Merged
merged 45 commits into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
f363848
NEP-491 reference implementation
jakmeier Jul 25, 2023
f101996
reject non-refundable transfer to existing account
jakmeier Jul 26, 2023
ab967fe
handle transferV2 in rosetta RPC
jakmeier Sep 26, 2023
75ca826
Merge remote-tracking branch 'upstream/master' into jakmeier/nep-491_…
jakmeier Sep 26, 2023
1b01356
refactor duplicate implicit account creation check
jakmeier Sep 26, 2023
03da556
cfg everything, add mapping to action view
jakmeier Sep 26, 2023
256a873
undo cfg on account version
jakmeier Sep 26, 2023
c85d091
fix test compilation errors
jakmeier Sep 26, 2023
1d4d270
reject new action in older protocol versions
jakmeier Sep 27, 2023
0a7fc9d
add nonrefundable field to `AccountView`
jakmeier Sep 27, 2023
b9f35ab
fix balance checker
jakmeier Sep 27, 2023
595e39f
add basic transfer_v2 test
jakmeier Sep 27, 2023
65304e9
propagate account view field in conversion
jakmeier Sep 27, 2023
0953f9a
Merge branch 'master' into nep-491_reference_implementation
Dec 7, 2023
aa34ee1
Resolve merge issues
Dec 13, 2023
a52fdb4
Fix compilation errors
staffik Dec 18, 2023
d67e91a
Merge remote-tracking branch 'origin/master' into nep-491_reference_i…
staffik Dec 18, 2023
ae36bae
Build fixes
staffik Dec 19, 2023
ac4b238
Parse genesis config as it have nonrefundable fields set to 0.
staffik Dec 19, 2023
1492711
Merge remote-tracking branch 'origin/master' into nep-491_reference_i…
staffik Dec 20, 2023
f9248d3
Fix nonrefundable_transfer test
staffik Dec 21, 2023
5773e44
Add missing Non-refundable transfer tests
staffik Jan 2, 2024
9c3b741
Update burnt amount on account deletion
staffik Jan 3, 2024
d42f125
Eth-implicit non-refundable transfer
staffik Jan 3, 2024
43d56b3
Introduce ReserveStorage action instead of deprecating the Transfer a…
staffik Jan 4, 2024
9e8948c
Fix the mainnet genesis hash issue
staffik Jan 9, 2024
b9dddbe
Add comements
staffik Jan 10, 2024
9cfaa00
No need to introduce Account variants
staffik Jan 10, 2024
9ffe5ad
Rename ReserveStorage --> NonrefundableStorageTransfer
staffik Jan 10, 2024
07a1fb4
Merge remote-tracking branch 'origin/master' into nep-491_reference_i…
staffik Jan 11, 2024
65b0175
Minor refactors, update test
staffik Jan 12, 2024
329dcd8
Both refundable and nonrefundable transfers
staffik Jan 22, 2024
2dfc544
Merge remote-tracking branch 'origin/master' into nep-491_reference_i…
staffik Jan 25, 2024
ffa1dc4
implicit_account_creation_eligible
staffik Jan 26, 2024
2350f3e
Merge remote-tracking branch 'origin/master' into nep-491_reference_i…
staffik Jan 26, 2024
5cbf7dc
Add comments
staffik Jan 26, 2024
77b47d2
Nit fixes
staffik Jan 29, 2024
c43bee3
Disable multiple transfers on implicit account creation
staffik Jan 29, 2024
69a2287
Use protocol version for Account::new()
staffik Jan 30, 2024
11f0b5e
PR fixes
staffik Feb 1, 2024
efa4c98
Merge remote-tracking branch 'origin/master' into nep-491_reference_i…
staffik Feb 1, 2024
0b1a097
Return error instead of panicking
staffik Feb 2, 2024
29d0f31
Merge remote-tracking branch 'origin/master' into nep-491_reference_i…
staffik Feb 15, 2024
38a7937
build fixes
staffik Feb 15, 2024
f49adef
Add tests
staffik Feb 15, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions chain/chain/src/test_utils/kv_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1242,8 +1242,10 @@ impl RuntimeAdapter for KeyValueRuntime {
|state| *state.amounts.get(account_id).unwrap_or(&0),
),
0,
0,
CryptoHash::default(),
0,
PROTOCOL_VERSION,
)
.into(),
),
Expand Down
4 changes: 2 additions & 2 deletions chain/chain/src/tests/simple_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ fn build_chain() {
// cargo insta test --accept -p near-chain --features nightly -- tests::simple_chain::build_chain
let hash = chain.head().unwrap().last_block_hash;
if cfg!(feature = "nightly") {
insta::assert_display_snapshot!(hash, @"DyeyWKAniYDFcxkf3n1VZdZfckguyvNs4qwoETYW2ofW");
insta::assert_display_snapshot!(hash, @"9JRdRkSfVRwYBVFNzfKwuhuUabMkQN14b1Ge7z1FRnMF");
} else {
insta::assert_display_snapshot!(hash, @"HJmRPXT4JM9tt6mXw2gM75YaSoqeDCphhFK26uRpd1vw");
}
Expand Down Expand Up @@ -82,7 +82,7 @@ fn build_chain() {

let hash = chain.head().unwrap().last_block_hash;
if cfg!(feature = "nightly") {
insta::assert_display_snapshot!(hash, @"NuKEKpsFRb3ZwTe9TtEuQcK1qkPKRBvkv8cNd9GrzN2");
insta::assert_display_snapshot!(hash, @"HkPEDHWJHuW8Yzw9FonrJarVAHi51mQt7A4DQUtBagko");
} else {
insta::assert_display_snapshot!(hash, @"HbQVGVZ3WGxsNqeM3GfSwDoxwYZ2RBP1SinAze9SYR3C");
}
Expand Down
21 changes: 20 additions & 1 deletion chain/client/src/test_utils/test_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use near_async::time::Clock;
use near_chain::test_utils::ValidatorSchedule;
use near_chain::{ChainGenesis, Provenance};
use near_chain_configs::GenesisConfig;
use near_chain_primitives::error::QueryError;
use near_chunks::client::ShardsManagerResponse;
use near_chunks::test_utils::{MockClientAdapterForShardsManager, SynchronousShardsManagerAdapter};
use near_crypto::{InMemorySigner, KeyType, Signer};
Expand All @@ -36,8 +37,10 @@ use near_primitives::types::{AccountId, Balance, BlockHeight, EpochId, NumSeats}
use near_primitives::utils::MaybeValidated;
use near_primitives::version::ProtocolVersion;
use near_primitives::views::{
AccountView, FinalExecutionOutcomeView, QueryRequest, QueryResponseKind, StateItem,
AccountView, FinalExecutionOutcomeView, QueryRequest, QueryResponse, QueryResponseKind,
StateItem,
};
use near_store::ShardUId;
use once_cell::sync::OnceCell;

use super::setup::setup_client_with_runtime;
Expand Down Expand Up @@ -462,6 +465,22 @@ impl TestEnv {
panic!("No client tracks shard {}", shard_id);
}

/// Passes the given query to the runtime adapter using the current head and returns a result.
pub fn query_view(&mut self, request: QueryRequest) -> Result<QueryResponse, QueryError> {
let head = self.clients[0].chain.head().unwrap();
let head_block = self.clients[0].chain.get_block(&head.last_block_hash).unwrap();
self.clients[0].runtime_adapter.query(
ShardUId::single_shard(),
&head_block.chunks()[0].prev_state_root(),
head.height,
0,
&head.prev_block_hash,
&head.last_block_hash,
head_block.header().epoch_id(),
&request,
)
}

pub fn query_state(&mut self, account_id: AccountId) -> Vec<StateItem> {
let client = &self.clients[0];
let head = client.chain.head().unwrap();
Expand Down
10 changes: 9 additions & 1 deletion chain/jsonrpc/res/rpc_errors_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@
"DelegateActionExpired",
"DelegateActionAccessKeyError",
"DelegateActionInvalidNonce",
"DelegateActionNonceTooLarge"
"DelegateActionNonceTooLarge",
"NonRefundableBalanceToExistingAccount"
],
"props": {
"index": ""
Expand Down Expand Up @@ -640,6 +641,13 @@
"subtypes": [],
"props": {}
},
"NonRefundableBalanceToExistingAccount": {
"name": "NonRefundableBalanceToExistingAccount",
"subtypes": [],
"props": {
"account_id": ""
}
},
"NonceTooLarge": {
"name": "NonceTooLarge",
"subtypes": [],
Expand Down
2 changes: 2 additions & 0 deletions chain/rosetta-rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ insta.workspace = true
near-actix-test-utils.workspace = true

[features]
protocol_feature_nonrefundable_transfer_nep491 = []
nightly_protocol = [
"near-actix-test-utils/nightly_protocol",
"near-chain-configs/nightly_protocol",
Expand All @@ -65,4 +66,5 @@ nightly = [
"near-primitives/nightly",
"nightly_protocol",
"node-runtime/nightly",
"protocol_feature_nonrefundable_transfer_nep491",
]
71 changes: 71 additions & 0 deletions chain/rosetta-rpc/src/adapters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,36 @@ impl From<NearActions> for Vec<crate::models::Operation> {
);
}

#[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")]
// Both refundable and non-refundable transfers are considered as available balance.
// TODO(nonrefundable) Merge with the arm above on stabilization.
near_primitives::transaction::Action::NonrefundableStorageTransfer(action) => {
let transfer_amount = crate::models::Amount::from_yoctonear(action.deposit);

let sender_transfer_operation_id =
crate::models::OperationIdentifier::new(&operations);
operations.push(
validated_operations::TransferOperation {
account: sender_account_identifier.clone(),
amount: -transfer_amount.clone(),
predecessor_id: Some(sender_account_identifier.clone()),
}
.into_operation(sender_transfer_operation_id.clone()),
);

operations.push(
validated_operations::TransferOperation {
account: receiver_account_identifier.clone(),
amount: transfer_amount,
predecessor_id: Some(sender_account_identifier.clone()),
}
.into_related_operation(
crate::models::OperationIdentifier::new(&operations),
vec![sender_transfer_operation_id],
),
);
}

near_primitives::transaction::Action::Stake(action) => {
operations.push(
validated_operations::StakeOperation {
Expand Down Expand Up @@ -837,6 +867,35 @@ mod tests {
use near_primitives::action::delegate::{DelegateAction, SignedDelegateAction};
use near_primitives::transaction::{Action, TransferAction};

#[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")]
#[test]
fn test_convert_nonrefundable_storage_transfer_action() {
let transfer_actions = vec![near_primitives::transaction::TransferAction {
deposit: near_primitives::types::Balance::MAX,
}
.into()];
let nonrefundable_transfer_actions =
vec![near_primitives::transaction::NonrefundableStorageTransferAction {
deposit: near_primitives::types::Balance::MAX,
}
.into()];
let near_transfer_actions = NearActions {
sender_account_id: "sender.near".parse().unwrap(),
receiver_account_id: "receiver.near".parse().unwrap(),
actions: transfer_actions,
};
let near_nonrefundable_transfer_actions = NearActions {
sender_account_id: "sender.near".parse().unwrap(),
receiver_account_id: "receiver.near".parse().unwrap(),
actions: nonrefundable_transfer_actions,
};
let transfer_operations_converted: Vec<crate::models::Operation> =
near_transfer_actions.into();
let nonrefundable_transfer_operations_converted: Vec<crate::models::Operation> =
near_nonrefundable_transfer_actions.into();
assert_eq!(transfer_operations_converted, nonrefundable_transfer_operations_converted);
}

#[test]
fn test_convert_block_changes_to_transactions() {
run_actix(async {
Expand All @@ -860,6 +919,8 @@ mod tests {
amount: 5000000000000000000,
code_hash: near_primitives::hash::CryptoHash::default(),
locked: 400000000000000000000000000000,
#[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")]
nonrefundable: 0,
storage_paid_at: 0,
storage_usage: 200000,
},
Expand All @@ -875,6 +936,8 @@ mod tests {
amount: 4000000000000000000,
code_hash: near_primitives::hash::CryptoHash::default(),
locked: 400000000000000000000000000000,
#[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")]
nonrefundable: 0,
storage_paid_at: 0,
storage_usage: 200000,
},
Expand All @@ -888,6 +951,8 @@ mod tests {
amount: 7000000000000000000,
code_hash: near_primitives::hash::CryptoHash::default(),
locked: 400000000000000000000000000000,
#[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")]
nonrefundable: 0,
storage_paid_at: 0,
storage_usage: 200000,
},
Expand All @@ -903,6 +968,8 @@ mod tests {
amount: 8000000000000000000,
code_hash: near_primitives::hash::CryptoHash::default(),
locked: 400000000000000000000000000000,
#[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")]
nonrefundable: 0,
storage_paid_at: 0,
storage_usage: 200000,
},
Expand All @@ -916,6 +983,8 @@ mod tests {
amount: 4000000000000000000,
code_hash: near_primitives::hash::CryptoHash::default(),
locked: 400000000000000000000000000000,
#[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")]
nonrefundable: 0,
storage_paid_at: 0,
storage_usage: 200000,
},
Expand All @@ -926,6 +995,8 @@ mod tests {
amount: 6000000000000000000,
code_hash: near_primitives::hash::CryptoHash::default(),
locked: 400000000000000000000000000000,
#[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")]
nonrefundable: 0,
storage_paid_at: 0,
storage_usage: 200000,
},
Expand Down
12 changes: 10 additions & 2 deletions chain/rosetta-rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub use config::RosettaRpcConfig;
use near_chain_configs::Genesis;
use near_client::{ClientActor, ViewClientActor};
use near_o11y::WithSpanContextExt;
use near_primitives::borsh::BorshDeserialize;
use near_primitives::{borsh::BorshDeserialize, version::PROTOCOL_VERSION};

mod adapters;
mod config;
Expand Down Expand Up @@ -368,7 +368,15 @@ async fn account_balance(
Err(crate::errors::ErrorKind::NotFound(_)) => (
block.header.hash,
block.header.height,
near_primitives::account::Account::new(0, 0, Default::default(), 0).into(),
near_primitives::account::Account::new(
0,
0,
0,
Default::default(),
0,
PROTOCOL_VERSION,
)
nagisa marked this conversation as resolved.
Show resolved Hide resolved
.into(),
),
Err(err) => return Err(err.into()),
};
Expand Down
24 changes: 22 additions & 2 deletions core/chain-configs/src/genesis_validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl<'a> GenesisValidator<'a> {
format!("Duplicate account id {} in genesis records", account_id);
self.validation_errors.push_genesis_semantics_error(error_message)
}
self.total_supply += account.locked() + account.amount();
self.total_supply += account.locked() + account.amount() + account.nonrefundable();
self.account_ids.insert(account_id.clone());
if account.locked() > 0 {
self.staked_accounts.insert(account_id.clone(), account.locked());
Expand Down Expand Up @@ -200,11 +200,31 @@ mod test {
use near_crypto::{KeyType, PublicKey};
use near_primitives::account::{AccessKey, Account};
use near_primitives::types::AccountInfo;
use near_primitives::version::PROTOCOL_VERSION;

const VALID_ED25519_RISTRETTO_KEY: &str = "ed25519:KuTCtARNzxZQ3YvXDeLjx83FDqxv2SdQTSbiq876zR7";

fn create_account() -> Account {
Account::new(100, 10, Default::default(), 0)
Account::new(100, 10, 0, Default::default(), 0, PROTOCOL_VERSION)
}

#[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")]
#[test]
fn test_total_supply_includes_nonrefundable_amount() {
let mut config = GenesisConfig::default();
config.epoch_length = 42;
config.total_supply = 111;
config.validators = vec![AccountInfo {
account_id: "test".parse().unwrap(),
public_key: VALID_ED25519_RISTRETTO_KEY.parse().unwrap(),
amount: 10,
}];
let records = GenesisRecords(vec![StateRecord::Account {
account_id: "test".parse().unwrap(),
account: Account::new(100, 10, 1, Default::default(), 0, PROTOCOL_VERSION),
}]);
let genesis = &Genesis::new(config, records).unwrap();
validate_genesis(genesis).unwrap();
}

#[test]
Expand Down
3 changes: 3 additions & 0 deletions core/primitives-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,20 @@ near-account-id.workspace = true
[dev-dependencies]
serde_json.workspace = true
insta.workspace = true
expect-test.workspace = true

[features]
default = []
protocol_feature_fix_staking_threshold = []
protocol_feature_fix_contract_loading_cost = []
protocol_feature_reject_blocks_with_outdated_protocol_version = []
protocol_feature_nonrefundable_transfer_nep491 = []

nightly = [
"nightly_protocol",
"protocol_feature_fix_contract_loading_cost",
"protocol_feature_fix_staking_threshold",
"protocol_feature_nonrefundable_transfer_nep491",
"protocol_feature_reject_blocks_with_outdated_protocol_version",
]

Expand Down
Loading
Loading