diff --git a/chain/rosetta-rpc/src/adapters/mod.rs b/chain/rosetta-rpc/src/adapters/mod.rs index 78335ae6949..f0cf14a2a97 100644 --- a/chain/rosetta-rpc/src/adapters/mod.rs +++ b/chain/rosetta-rpc/src/adapters/mod.rs @@ -500,8 +500,9 @@ impl From for Vec { operations.extend(delegated_operations); } // TODO(#8469): Implement delegate action support, for now they are ignored. - near_primitives::transaction::Action::DeployGlobalContract(_action) => { - // TODO(#12639): Implement global contract deploys support, ignored for now. + near_primitives::transaction::Action::DeployGlobalContract(_) + | near_primitives::transaction::Action::UseGlobalContract(_) => { + // TODO(#12639): Implement global contracts support, ignored for now. } } } diff --git a/core/primitives/src/action/mod.rs b/core/primitives/src/action/mod.rs index a250f7465d1..26be1357718 100644 --- a/core/primitives/src/action/mod.rs +++ b/core/primitives/src/action/mod.rs @@ -4,6 +4,7 @@ use borsh::{BorshDeserialize, BorshSerialize}; use near_crypto::PublicKey; use near_primitives_core::{ account::AccessKey, + hash::CryptoHash, serialize::dec_format, types::{AccountId, Balance, Gas}, }; @@ -159,6 +160,40 @@ impl fmt::Debug for DeployGlobalContractAction { } } +#[serde_as] +#[derive( + BorshSerialize, + BorshDeserialize, + serde::Serialize, + serde::Deserialize, + PartialEq, + Eq, + Clone, + ProtocolSchema, + Debug, +)] +pub enum GlobalContractIdentifier { + CodeHash(CryptoHash), + AccountId(AccountId), +} + +/// Use global contract action +#[serde_as] +#[derive( + BorshSerialize, + BorshDeserialize, + serde::Serialize, + serde::Deserialize, + PartialEq, + Eq, + Clone, + ProtocolSchema, + Debug, +)] +pub struct UseGlobalContractAction { + pub contract_identifier: GlobalContractIdentifier, +} + #[serde_as] #[derive( BorshSerialize, @@ -270,6 +305,7 @@ pub enum Action { DeleteAccount(DeleteAccountAction), Delegate(Box), DeployGlobalContract(DeployGlobalContractAction), + UseGlobalContract(Box), #[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")] /// Makes a non-refundable transfer for storage allowance. /// Only possible during new account creation. diff --git a/core/primitives/src/views.rs b/core/primitives/src/views.rs index bc247fe1c95..07c5bacd948 100644 --- a/core/primitives/src/views.rs +++ b/core/primitives/src/views.rs @@ -5,7 +5,10 @@ //! from the source structure in the relevant `From` impl. use crate::account::{AccessKey, AccessKeyPermission, Account, FunctionCallPermission}; use crate::action::delegate::{DelegateAction, SignedDelegateAction}; -use crate::action::{DeployGlobalContractAction, GlobalContractDeployMode}; +use crate::action::{ + DeployGlobalContractAction, GlobalContractDeployMode, GlobalContractIdentifier, + UseGlobalContractAction, +}; use crate::bandwidth_scheduler::BandwidthRequests; use crate::block::{Block, BlockHeader, Tip}; use crate::block_header::BlockHeaderInnerLite; @@ -1179,6 +1182,12 @@ pub enum ActionView { #[serde_as(as = "Base64")] code: Vec, }, + UseGlobalContract { + code_hash: CryptoHash, + }, + UseGlobalContractByAccountId { + account_id: AccountId, + }, } impl From for ActionView { @@ -1224,6 +1233,14 @@ impl From for ActionView { } } } + Action::UseGlobalContract(action) => match action.contract_identifier { + GlobalContractIdentifier::CodeHash(code_hash) => { + ActionView::UseGlobalContract { code_hash } + } + GlobalContractIdentifier::AccountId(account_id) => { + ActionView::UseGlobalContractByAccountId { account_id } + } + }, } } } @@ -1277,6 +1294,16 @@ impl TryFrom for Action { deploy_mode: GlobalContractDeployMode::AccountId, }) } + ActionView::UseGlobalContract { code_hash } => { + Action::UseGlobalContract(Box::new(UseGlobalContractAction { + contract_identifier: GlobalContractIdentifier::CodeHash(code_hash), + })) + } + ActionView::UseGlobalContractByAccountId { account_id } => { + Action::UseGlobalContract(Box::new(UseGlobalContractAction { + contract_identifier: GlobalContractIdentifier::AccountId(account_id), + })) + } }) } } diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index 4ffecb82b36..6cfcdf6a649 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -9,7 +9,7 @@ use near_crypto::PublicKey; use near_parameters::{AccountCreationConfig, ActionCosts, RuntimeConfig, RuntimeFeesConfig}; use near_primitives::account::{AccessKey, AccessKeyPermission, Account}; use near_primitives::action::delegate::{DelegateAction, SignedDelegateAction}; -use near_primitives::action::DeployGlobalContractAction; +use near_primitives::action::{DeployGlobalContractAction, UseGlobalContractAction}; use near_primitives::checked_feature; use near_primitives::config::ViewConfig; use near_primitives::errors::{ActionError, ActionErrorKind, InvalidAccessKeyError, RuntimeError}; @@ -664,6 +664,16 @@ pub(crate) fn action_deploy_global_contract( Ok(()) } +pub(crate) fn action_use_global_contract( + _state_update: &mut TrieUpdate, + _account: &mut Account, + _action: &UseGlobalContractAction, +) -> Result<(), RuntimeError> { + let _span = tracing::debug_span!(target: "runtime", "action_use_global_contract").entered(); + // TODO(#12716): implement global contract usage + Ok(()) +} + pub(crate) fn action_delete_account( state_update: &mut TrieUpdate, account: &mut Option, @@ -1040,7 +1050,8 @@ pub(crate) fn check_actor_permissions( | Action::Stake(_) | Action::AddKey(_) | Action::DeleteKey(_) - | Action::DeployGlobalContract(_) => { + | Action::DeployGlobalContract(_) + | Action::UseGlobalContract(_) => { if actor_id != account_id { return Err(ActionErrorKind::ActorNoPermission { account_id: account_id.clone(), @@ -1153,7 +1164,8 @@ pub(crate) fn check_account_existence( | Action::DeleteKey(_) | Action::DeleteAccount(_) | Action::Delegate(_) - | Action::DeployGlobalContract(_) => { + | Action::DeployGlobalContract(_) + | Action::UseGlobalContract(_) => { if account.is_none() { return Err(ActionErrorKind::AccountDoesNotExist { account_id: account_id.clone(), diff --git a/runtime/runtime/src/config.rs b/runtime/runtime/src/config.rs index d2fca9d17e2..11cbf568a14 100644 --- a/runtime/runtime/src/config.rs +++ b/runtime/runtime/src/config.rs @@ -150,8 +150,8 @@ pub fn total_send_fees( &delegate_action.receiver_id, )? } - DeployGlobalContract(_deploy_global_contract_action) => { - // TODO(#12717): implement send fees for global contract deploy + DeployGlobalContract(_) | UseGlobalContract(_) => { + // TODO(#12717): implement send fees for global contracts 1 } }; @@ -245,8 +245,8 @@ pub fn exec_fee(config: &RuntimeConfig, action: &Action, receiver_id: &AccountId DeleteKey(_) => fees.fee(ActionCosts::delete_key).exec_fee(), DeleteAccount(_) => fees.fee(ActionCosts::delete_account).exec_fee(), Delegate(_) => fees.fee(ActionCosts::delegate).exec_fee(), - DeployGlobalContract(_deploy_global_contract_action) => { - // TODO(#12717): implement exec fees for global contract deploys + DeployGlobalContract(_) | UseGlobalContract(_) => { + // TODO(#12717): implement exec fees for global contracts 1 } } diff --git a/runtime/runtime/src/lib.rs b/runtime/runtime/src/lib.rs index 443edfce462..ec7caa8c8b9 100644 --- a/runtime/runtime/src/lib.rs +++ b/runtime/runtime/src/lib.rs @@ -487,6 +487,10 @@ impl Runtime { Action::DeployGlobalContract(deploy_global_contract) => { action_deploy_global_contract(account_id, deploy_global_contract, &mut result)?; } + Action::UseGlobalContract(use_global_contract) => { + let account = account.as_mut().expect(EXPECT_ACCOUNT_EXISTS); + action_use_global_contract(state_update, account, use_global_contract)?; + } Action::FunctionCall(function_call) => { let account = account.as_mut().expect(EXPECT_ACCOUNT_EXISTS); let contract = preparation_pipeline.get_contract( diff --git a/runtime/runtime/src/pipelining.rs b/runtime/runtime/src/pipelining.rs index f1448537610..0f2cb2d5f73 100644 --- a/runtime/runtime/src/pipelining.rs +++ b/runtime/runtime/src/pipelining.rs @@ -126,7 +126,7 @@ impl ReceiptPreparationPipeline { for (action_index, action) in actions.iter().enumerate() { let account_id = account_id.clone(); match action { - Action::DeployContract(_) => { + Action::DeployContract(_) | Action::UseGlobalContract(_) => { // FIXME: instead of blocking these accounts, move the handling of // deploy action into here, so that the necessary data dependencies can be // established. diff --git a/runtime/runtime/src/verifier.rs b/runtime/runtime/src/verifier.rs index c625933f577..ffbd017e7cb 100644 --- a/runtime/runtime/src/verifier.rs +++ b/runtime/runtime/src/verifier.rs @@ -437,6 +437,9 @@ pub fn validate_action( Action::DeployGlobalContract(a) => { validate_deploy_global_contract_action(limit_config, a, current_protocol_version) } + Action::UseGlobalContract(_) => { + validate_use_global_contract_action(current_protocol_version) + } Action::FunctionCall(a) => validate_function_call_action(limit_config, a), Action::Transfer(_) => Ok(()), #[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")] @@ -482,12 +485,8 @@ fn validate_deploy_global_contract_action( action: &DeployGlobalContractAction, current_protocol_version: ProtocolVersion, ) -> Result<(), ActionsValidationError> { - if !checked_feature!("stable", GlobalContracts, current_protocol_version) { - return Err(ActionsValidationError::UnsupportedProtocolFeature { - protocol_feature: "GlobalContracts".to_owned(), - version: current_protocol_version, - }); - } + check_global_contracts_enabled(current_protocol_version)?; + if action.code.len() as u64 > limit_config.max_contract_size { return Err(ActionsValidationError::ContractSizeExceeded { size: action.code.len() as u64, @@ -498,6 +497,13 @@ fn validate_deploy_global_contract_action( Ok(()) } +/// Validates `UseGlobalContractAction`. +fn validate_use_global_contract_action( + current_protocol_version: ProtocolVersion, +) -> Result<(), ActionsValidationError> { + check_global_contracts_enabled(current_protocol_version) +} + /// Validates `FunctionCallAction`. Checks that the method name length doesn't exceed the limit and /// the length of the arguments doesn't exceed the limit. fn validate_function_call_action( @@ -618,6 +624,18 @@ fn truncate_string(s: &str, limit: usize) -> String { unreachable!() } +fn check_global_contracts_enabled( + current_protocol_version: ProtocolVersion, +) -> Result<(), ActionsValidationError> { + if !checked_feature!("stable", GlobalContracts, current_protocol_version) { + return Err(ActionsValidationError::UnsupportedProtocolFeature { + protocol_feature: "GlobalContracts".to_owned(), + version: current_protocol_version, + }); + } + Ok(()) +} + #[cfg(test)] mod tests { use std::sync::Arc; diff --git a/tools/protocol-schema-check/res/protocol_schema.toml b/tools/protocol-schema-check/res/protocol_schema.toml index f8b89209605..671a645c606 100644 --- a/tools/protocol-schema-check/res/protocol_schema.toml +++ b/tools/protocol-schema-check/res/protocol_schema.toml @@ -3,11 +3,11 @@ AccessKeyPermission = 885623561 Account = 358811118 AccountV2 = 337859929 AccountVersion = 4249996519 -Action = 776842263 +Action = 3388998117 ActionCosts = 3115555891 ActionError = 4217425219 ActionErrorKind = 1632922469 -ActionReceipt = 1557869689 +ActionReceipt = 4271134158 ActionsValidationError = 1053886215 AddKeyAction = 356099649 AdvertisedPeerDistance = 1372421497 @@ -53,8 +53,8 @@ BlockV4 = 619721361 BlockWithChangesInfo = 887507517 BufferedReceiptIndices = 2030010377 CachedParts = 1180507252 -Challenge = 790871821 -ChallengeBody = 3913931329 +Challenge = 3843626341 +ChallengeBody = 289148653 ChunkContractAccesses = 266426785 ChunkContractAccessesInner = 2811580521 ChunkContractAccessesV1 = 3680796018 @@ -68,10 +68,10 @@ ChunkExtraV1 = 774877102 ChunkHash = 1471814478 ChunkHashHeight = 825215623 ChunkProductionKey = 2508733236 -ChunkProofs = 2621917485 -ChunkState = 4147907071 +ChunkProofs = 4167933191 +ChunkState = 490815833 ChunkStateTransition = 307448170 -ChunkStateWitness = 2948089286 +ChunkStateWitness = 3044594480 ChunkStateWitnessAck = 177881908 ChunkStats = 4176245277 CodeBytes = 2940589161 @@ -95,7 +95,7 @@ CurrentEpochValidatorInfo = 434177728 DataReceipt = 2506806701 DataReceiver = 1715762664 DelayedReceiptIndices = 1315689119 -DelegateAction = 1467185064 +DelegateAction = 1159009392 DeleteAccountAction = 3244670577 DeleteKeyAction = 1374597333 DeployContractAction = 2972267833 @@ -145,6 +145,7 @@ FunctionCallAction = 2405840012 FunctionCallError = 3652274053 FunctionCallPermission = 1517509673 GlobalContractDeployMode = 1256912586 +GlobalContractIdentifier = 31664100 Handshake = 115352275 HandshakeAutoDes = 4093619285 HandshakeFailureReason = 3698375404 @@ -159,22 +160,22 @@ LatestWitnessesInfo = 2488443612 LegacyAccount = 1291371319 LinkAllowance = 1652755161 MainTransitionKey = 3721480128 -MaybeEncodedShardChunk = 2470055256 +MaybeEncodedShardChunk = 2483515710 MerklePathItem = 2615629611 MessageDiscriminant = 3240833245 MethodResolveError = 1206790835 MissingTrieValueContext = 2666011379 NextEpochValidatorInfo = 3660299258 -NonDelegateAction = 705924980 +NonDelegateAction = 2970737551 ParentSplitParameters = 2945469052 PartialEdgeInfo = 1350359189 -PartialEncodedChunk = 2463323471 +PartialEncodedChunk = 2321210648 PartialEncodedChunkForwardMsg = 68012243 PartialEncodedChunkPart = 194051090 PartialEncodedChunkRequestMsg = 1470767646 -PartialEncodedChunkResponseMsg = 4085260276 -PartialEncodedChunkV1 = 872351009 -PartialEncodedChunkV2 = 2201750036 +PartialEncodedChunkResponseMsg = 2470689017 +PartialEncodedChunkV1 = 4160916755 +PartialEncodedChunkV2 = 2900885561 PartialEncodedContractDeploys = 3216562245 PartialEncodedContractDeploysInner = 2549441552 PartialEncodedContractDeploysPart = 1672852427 @@ -186,7 +187,7 @@ PeerChainInfoV2 = 1260985250 PeerId = 2447445523 PeerIdOrHash = 4080492546 PeerInfo = 3831734408 -PeerMessage = 3436033484 +PeerMessage = 2103502471 Ping = 2783493472 Pong = 3159638327 PrepareError = 4009037507 @@ -200,28 +201,28 @@ RawStateChangesWithTrieKey = 36781564 RawTrieNode = 4239211001 RawTrieNodeWithSize = 1474149765 ReasonForBan = 792112981 -Receipt = 2204437923 -ReceiptEnum = 363966149 +Receipt = 1699385171 +ReceiptEnum = 2951652014 ReceiptGroup = 2105921101 ReceiptGroupV0 = 2900361850 ReceiptGroupsQueueData = 289073248 ReceiptGroupsQueueDataV0 = 3449687695 ReceiptList = 3805749482 -ReceiptOrStateStoredReceipt = 1445320664 -ReceiptProof = 3654203090 -ReceiptProofResponse = 1538369673 -ReceiptV0 = 2579978250 -ReceiptV1 = 2410814374 +ReceiptOrStateStoredReceipt = 2995655728 +ReceiptProof = 414952087 +ReceiptProofResponse = 1563585870 +ReceiptV0 = 3701801574 +ReceiptV1 = 2838991728 ReceiptValidationError = 551721215 ReceivedData = 3601438283 RootProof = 3135729669 -RoutedMessage = 1371676559 -RoutedMessageBody = 720213720 +RoutedMessage = 3890844808 +RoutedMessageBody = 4077508749 RoutingTableUpdate = 2987752645 Secp256K1PublicKey = 4117078281 Secp256K1Signature = 3687154735 ServerError = 2338793369 -ShardChunk = 2569066311 +ShardChunk = 2682019119 ShardChunkHeader = 2471921769 ShardChunkHeaderInner = 4085026561 ShardChunkHeaderInnerV1 = 1271245459 @@ -231,22 +232,22 @@ ShardChunkHeaderInnerV4 = 3066669719 ShardChunkHeaderV1 = 47891389 ShardChunkHeaderV2 = 226996174 ShardChunkHeaderV3 = 3315420662 -ShardChunkV1 = 1687626581 -ShardChunkV2 = 3129653406 +ShardChunkV1 = 1882971601 +ShardChunkV2 = 736427760 ShardLayout = 1639977238 ShardLayoutV0 = 3139625127 ShardLayoutV1 = 2054829142 ShardLayoutV2 = 997571636 ShardProof = 1787648268 -ShardStateSyncResponse = 36151067 -ShardStateSyncResponseHeaderV1 = 3239482057 -ShardStateSyncResponseHeaderV2 = 2990843176 -ShardStateSyncResponseV1 = 818774996 -ShardStateSyncResponseV2 = 3658187594 -ShardStateSyncResponseV3 = 4290351817 +ShardStateSyncResponse = 998212107 +ShardStateSyncResponseHeaderV1 = 116351680 +ShardStateSyncResponseHeaderV2 = 3773572367 +ShardStateSyncResponseV1 = 2266739500 +ShardStateSyncResponseV2 = 2597002549 +ShardStateSyncResponseV3 = 3607001423 ShardUId = 2410086023 Signature = 3997391707 -SignedDelegateAction = 2481674346 +SignedDelegateAction = 590117931 SignedTransaction = 3898692301 SlashState = 3264273950 SlashedValidator = 2601657743 @@ -256,14 +257,14 @@ StateChangeCause = 3890585134 StateHeaderKey = 1666317019 StatePartKey = 1083277414 StatePartRequest = 1911936050 -StateResponseInfo = 725797617 -StateResponseInfoV1 = 1157694409 -StateResponseInfoV2 = 1173349517 +StateResponseInfo = 1422704909 +StateResponseInfoV1 = 2569959725 +StateResponseInfoV2 = 3097863223 StateRootNode = 1865105129 -StateStoredReceipt = 1819790166 +StateStoredReceipt = 1314929805 StateStoredReceiptMetadata = 2895538362 -StateStoredReceiptV0 = 705939741 -StateStoredReceiptV1 = 1187482238 +StateStoredReceiptV0 = 2639551962 +StateStoredReceiptV1 = 3829861961 StateSyncDumpProgress = 2225888613 StorageError = 2572184728 StoredChunkStateTransitionData = 102691676 @@ -271,9 +272,9 @@ StoredChunkStateTransitionDataV1 = 3220541377 String = 2587724713 SyncSnapshotHosts = 1436852332 Tip = 305642482 -TransactionReceipt = 413230486 -TransactionV0 = 1428493041 -TransactionV1 = 442421785 +TransactionReceipt = 1139314092 +TransactionV0 = 2318136898 +TransactionV1 = 2359321608 TransferAction = 1078380396 TrieChanges = 2613580820 TrieKey = 1352104737 @@ -281,6 +282,7 @@ TrieQueueIndices = 2601394796 TrieRefcountAddition = 2117109883 TrieRefcountSubtraction = 2150368599 TxExecutionError = 214948980 +UseGlobalContractAction = 4227348133 VMKind = 2110212047 ValidatorKickoutReason = 2362237969 ValidatorKickoutView = 2660746751 diff --git a/tools/state-viewer/src/contract_accounts.rs b/tools/state-viewer/src/contract_accounts.rs index cb230760258..3f55a18170e 100644 --- a/tools/state-viewer/src/contract_accounts.rs +++ b/tools/state-viewer/src/contract_accounts.rs @@ -137,6 +137,7 @@ pub(crate) enum ActionType { DataReceipt, Delegate, DeployGlobalContract, + UseGlobalContract, } impl ContractAccount { @@ -352,6 +353,7 @@ fn try_find_actions_spawned_by_receipt( Action::DeployGlobalContract(_) => { ActionType::DeployGlobalContract } + Action::UseGlobalContract(_) => ActionType::UseGlobalContract, }; entry .actions