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

global contracts prototype #12648

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
35 changes: 25 additions & 10 deletions chain/chain/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4427,9 +4427,15 @@ impl Chain {
) -> HashMap<ShardId, Vec<Receipt>> {
let mut result = HashMap::new();
for receipt in receipts {
let shard_id = shard_layout.account_id_to_shard_id(receipt.receiver_id());
let entry = result.entry(shard_id).or_insert_with(Vec::new);
entry.push(receipt)
if receipt.send_to_all_shards() {
for shard_id in shard_layout.shard_ids() {
result.entry(shard_id).or_insert_with(Vec::new).push(receipt.clone());
}
} else {
let shard_id = shard_layout.account_id_to_shard_id(receipt.receiver_id());
let entry = result.entry(shard_id).or_insert_with(Vec::new);
entry.push(receipt);
}
}
result
}
Expand All @@ -4450,13 +4456,22 @@ impl Chain {
}
let mut cache = HashMap::new();
for receipt in receipts {
let &mut shard_id = cache
.entry(receipt.receiver_id())
.or_insert_with(|| shard_layout.account_id_to_shard_id(receipt.receiver_id()));
// This unwrap should be safe as we pre-populated the map with all
// valid shard ids.
let shard_index = shard_layout.get_shard_index(shard_id).unwrap();
result_map.get_mut(&shard_index).unwrap().1.push(receipt);
if receipt.send_to_all_shards() {
for shard_id in shard_layout.shard_ids() {
// This unwrap should be safe as we pre-populated the map with all
// valid shard ids.
let shard_index = shard_layout.get_shard_index(shard_id).unwrap();
result_map.get_mut(&shard_index).unwrap().1.push(receipt);
}
} else {
let &mut shard_id = cache
.entry(receipt.receiver_id())
.or_insert_with(|| shard_layout.account_id_to_shard_id(receipt.receiver_id()));
// This unwrap should be safe as we pre-populated the map with all
// valid shard ids.
let shard_index = shard_layout.get_shard_index(shard_id).unwrap();
result_map.get_mut(&shard_index).unwrap().1.push(receipt);
};
}

let mut result_vec = vec![];
Expand Down
3 changes: 2 additions & 1 deletion chain/chain/src/flat_storage_resharder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -994,7 +994,8 @@ fn shard_split_handle_key_value(
col::DELAYED_RECEIPT_OR_INDICES
| col::PROMISE_YIELD_INDICES
| col::PROMISE_YIELD_TIMEOUT
| col::BANDWIDTH_SCHEDULER_STATE => {
| col::BANDWIDTH_SCHEDULER_STATE
| col::GLOBAL_CONTRACT_DATA => {
copy_kv_to_all_children(&split_params, key, value, store_update)
}
col::BUFFERED_RECEIPT_INDICES | col::BUFFERED_RECEIPT => {
Expand Down
10 changes: 8 additions & 2 deletions chain/chain/src/runtime/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,8 +372,14 @@ impl TestEnv {
let shard_layout = self.epoch_manager.get_shard_layout_from_prev_block(&new_hash).unwrap();
let mut new_receipts = HashMap::<_, Vec<Receipt>>::new();
for receipt in all_receipts {
let shard_id = shard_layout.account_id_to_shard_id(receipt.receiver_id());
new_receipts.entry(shard_id).or_default().push(receipt);
if receipt.send_to_all_shards() {
for shard_id in shard_layout.shard_ids() {
new_receipts.entry(shard_id).or_default().push(receipt.clone());
}
} else {
let shard_id = shard_layout.account_id_to_shard_id(receipt.receiver_id());
new_receipts.entry(shard_id).or_default().push(receipt);
}
}
self.last_receipts = new_receipts;
self.last_proposals = all_proposals;
Expand Down
7 changes: 4 additions & 3 deletions chain/chain/src/store/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,9 +387,10 @@ pub fn filter_incoming_receipts_for_shard(
let mut filtered_receipts = vec![];
let ReceiptProof(receipts, shard_proof) = receipt_proof.clone();
for receipt in receipts {
let receiver_shard_id =
target_shard_layout.account_id_to_shard_id(receipt.receiver_id());
if receiver_shard_id == target_shard_id {
if receipt.send_to_all_shards()
|| target_shard_layout.account_id_to_shard_id(receipt.receiver_id())
== target_shard_id
{
tracing::trace!(target: "chain", receipt_id=?receipt.receipt_id(), "including receipt");
filtered_receipts.push(receipt);
} else {
Expand Down
3 changes: 2 additions & 1 deletion chain/chain/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,8 @@ mod test {
let shard_receipts: Vec<Receipt> = receipts
.iter()
.filter(|&receipt| {
shard_layout.account_id_to_shard_id(receipt.receiver_id()) == shard_id
receipt.send_to_all_shards()
|| shard_layout.account_id_to_shard_id(receipt.receiver_id()) == shard_id
})
.cloned()
.collect();
Expand Down
4 changes: 4 additions & 0 deletions chain/rosetta-rpc/src/adapters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,10 @@ impl From<NearActions> for Vec<crate::models::Operation> {

operations.extend(delegated_operations);
} // TODO(#8469): Implement delegate action support, for now they are ignored.
near_primitives::action::Action::DeployGlobalContract(_)
| near_primitives::action::Action::UseGlobalContract(_) => {
// TODO(#12639): Implement global contracts support, ignored for now
}
}
}
operations
Expand Down
47 changes: 46 additions & 1 deletion core/primitives/src/action/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
};
Expand All @@ -12,7 +13,7 @@ use serde_with::base64::Base64;
use serde_with::serde_as;
use std::fmt;

fn base64(s: &[u8]) -> String {
pub fn base64(s: &[u8]) -> String {
use base64::Engine;
base64::engine::general_purpose::STANDARD.encode(s)
}
Expand Down Expand Up @@ -106,6 +107,48 @@ impl fmt::Debug for DeployContractAction {
}
}

/// Deploy global contract action
#[serde_as]
#[derive(
BorshSerialize,
BorshDeserialize,
serde::Serialize,
serde::Deserialize,
PartialEq,
Eq,
Clone,
ProtocolSchema,
)]
pub struct DeployGlobalContractAction {
/// WebAssembly binary
#[serde_as(as = "Base64")]
pub code: Vec<u8>,
}

impl fmt::Debug for DeployGlobalContractAction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("DeployGlobalContractAction")
.field("code", &format_args!("{}", base64(&self.code)))
.finish()
}
}

#[serde_as]
#[derive(
BorshSerialize,
BorshDeserialize,
serde::Serialize,
serde::Deserialize,
PartialEq,
Eq,
Clone,
ProtocolSchema,
Debug,
)]
pub struct UseGlobalContractAction {
pub global_code_hash: CryptoHash,
}

#[serde_as]
#[derive(
BorshSerialize,
Expand Down Expand Up @@ -216,6 +259,8 @@ pub enum Action {
DeleteKey(Box<DeleteKeyAction>),
DeleteAccount(DeleteAccountAction),
Delegate(Box<delegate::SignedDelegateAction>),
DeployGlobalContract(DeployGlobalContractAction),
UseGlobalContract(Box<UseGlobalContractAction>),
#[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")]
/// Makes a non-refundable transfer for storage allowance.
/// Only possible during new account creation.
Expand Down
39 changes: 39 additions & 0 deletions core/primitives/src/receipt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,10 @@ impl Receipt {
*self.receipt_id()
}

pub fn send_to_all_shards(&self) -> bool {
matches!(self.receipt(), ReceiptEnum::GlobalContractDitribution(..))
}

/// Generates a receipt with a transfer from system for a given balance without a receipt_id.
/// This should be used for token refunds instead of gas refunds. It inherits priority from the parent receipt.
/// It doesn't refund the allowance of the access key. For gas refunds use `new_gas_refund`.
Expand Down Expand Up @@ -571,6 +575,15 @@ impl Receipt {
}),
}
}

pub fn new_global_contract_distribution(predecessor_id: AccountId, code: Vec<u8>) -> Self {
Self::V0(ReceiptV0 {
predecessor_id,
receiver_id: "system".parse().unwrap(),
receipt_id: CryptoHash::default(),
receipt: ReceiptEnum::GlobalContractDitribution(GlobalContractData { code: code }),
})
}
}

/// Receipt could be either ActionReceipt or DataReceipt
Expand All @@ -590,6 +603,7 @@ pub enum ReceiptEnum {
Data(DataReceipt),
PromiseYield(ActionReceipt),
PromiseResume(DataReceipt),
GlobalContractDitribution(GlobalContractData),
}

/// ActionReceipt is derived from an Action from `Transaction or from Receipt`
Expand Down Expand Up @@ -670,6 +684,31 @@ impl fmt::Debug for ReceivedData {
}
}

#[serde_as]
#[derive(
BorshSerialize,
BorshDeserialize,
Hash,
PartialEq,
Eq,
Clone,
serde::Serialize,
serde::Deserialize,
ProtocolSchema,
)]
pub struct GlobalContractData {
#[serde_as(as = "Base64")]
pub code: Vec<u8>,
}

impl fmt::Debug for GlobalContractData {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("GlobalContractData")
//.field("code", &format_args!("{}", base64(&self.code)))
.finish()
}
}

/// Stores indices for a persistent queue for delayed receipts that didn't fit into a block.
#[derive(Default, BorshSerialize, BorshDeserialize, Clone, PartialEq, Debug, ProtocolSchema)]
pub struct DelayedReceiptIndices {
Expand Down
15 changes: 14 additions & 1 deletion core/primitives/src/trie_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ pub mod col {
pub const BUFFERED_RECEIPT_GROUPS_QUEUE_DATA: u8 = 16;
/// A single item of `ReceiptGroupsQueue`. Values are of type `ReceiptGroup`.
pub const BUFFERED_RECEIPT_GROUPS_QUEUE_ITEM: u8 = 17;
pub const GLOBAL_CONTRACT_DATA: u8 = 18;

/// All columns except those used for the delayed receipts queue, the yielded promises
/// queue, and the outgoing receipts buffer, which are global state for the shard.
Expand All @@ -77,7 +78,7 @@ pub mod col {
(PROMISE_YIELD_RECEIPT, "PromiseYieldReceipt"),
];

pub const ALL_COLUMNS_WITH_NAMES: [(u8, &'static str); 17] = [
pub const ALL_COLUMNS_WITH_NAMES: [(u8, &'static str); 18] = [
(ACCOUNT, "Account"),
(CONTRACT_CODE, "ContractCode"),
(ACCESS_KEY, "AccessKey"),
Expand All @@ -95,6 +96,7 @@ pub mod col {
(BANDWIDTH_SCHEDULER_STATE, "BandwidthSchedulerState"),
(BUFFERED_RECEIPT_GROUPS_QUEUE_DATA, "BufferedReceiptGroupsQueueData"),
(BUFFERED_RECEIPT_GROUPS_QUEUE_ITEM, "BufferedReceiptGroupsQueueItem"),
(GLOBAL_CONTRACT_DATA, "GlobalContractData"),
];
}

Expand Down Expand Up @@ -193,6 +195,9 @@ pub enum TrieKey {
receiving_shard: ShardId,
index: u64,
},
GlobalContractCode {
code_hash: CryptoHash,
},
}

/// Provides `len` function.
Expand Down Expand Up @@ -277,6 +282,9 @@ impl TrieKey {
+ std::mem::size_of::<u64>()
+ std::mem::size_of_val(index)
}
TrieKey::GlobalContractCode { code_hash } => {
col::GLOBAL_CONTRACT_DATA.len() + code_hash.as_ref().len()
}
}
}

Expand Down Expand Up @@ -370,6 +378,10 @@ impl TrieKey {
buf.extend(&receiving_shard.to_le_bytes());
buf.extend(&index.to_le_bytes());
}
TrieKey::GlobalContractCode { code_hash } => {
buf.push(col::GLOBAL_CONTRACT_DATA);
buf.extend(code_hash.as_ref());
}
};
debug_assert_eq!(expected_len, buf.len() - start_len);
}
Expand Down Expand Up @@ -401,6 +413,7 @@ impl TrieKey {
TrieKey::BandwidthSchedulerState => None,
TrieKey::BufferedReceiptGroupsQueueData { .. } => None,
TrieKey::BufferedReceiptGroupsQueueItem { .. } => None,
TrieKey::GlobalContractCode { .. } => None,
}
}
}
Expand Down
1 change: 1 addition & 0 deletions core/primitives/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ impl StateChanges {
TrieKey::BandwidthSchedulerState => {}
TrieKey::BufferedReceiptGroupsQueueData { .. } => {}
TrieKey::BufferedReceiptGroupsQueueItem { .. } => {}
TrieKey::GlobalContractCode { .. } => {}
}
}

Expand Down
21 changes: 21 additions & 0 deletions core/primitives/src/views.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
//! from the source structure in the relevant `From<SourceStruct>` impl.
use crate::account::{AccessKey, AccessKeyPermission, Account, FunctionCallPermission};
use crate::action::delegate::{DelegateAction, SignedDelegateAction};
use crate::action::{DeployGlobalContractAction, UseGlobalContractAction};
use crate::bandwidth_scheduler::BandwidthRequests;
use crate::block::{Block, BlockHeader, Tip};
use crate::block_header::BlockHeaderInnerLite;
Expand Down Expand Up @@ -1170,6 +1171,13 @@ pub enum ActionView {
delegate_action: DelegateAction,
signature: Signature,
},
DeployGlobalContract {
#[serde_as(as = "Base64")]
code: Vec<u8>,
},
UseGlobalContract {
global_code_hash: CryptoHash,
},
}

impl From<Action> for ActionView {
Expand Down Expand Up @@ -1206,6 +1214,12 @@ impl From<Action> for ActionView {
delegate_action: action.delegate_action,
signature: action.signature,
},
Action::DeployGlobalContract(action) => {
ActionView::DeployGlobalContract { code: action.code }
}
Action::UseGlobalContract(action) => {
ActionView::UseGlobalContract { global_code_hash: action.global_code_hash }
}
}
}
}
Expand Down Expand Up @@ -1247,6 +1261,12 @@ impl TryFrom<ActionView> for Action {
ActionView::Delegate { delegate_action, signature } => {
Action::Delegate(Box::new(SignedDelegateAction { delegate_action, signature }))
}
ActionView::DeployGlobalContract { code } => {
Action::DeployGlobalContract(DeployGlobalContractAction { code })
}
ActionView::UseGlobalContract { global_code_hash } => {
Action::UseGlobalContract(Box::new(UseGlobalContractAction { global_code_hash }))
}
})
}
}
Expand Down Expand Up @@ -1953,6 +1973,7 @@ impl From<Receipt> for ReceiptView {
is_promise_resume,
}
}
ReceiptEnum::GlobalContractDitribution(_) => todo!("#12639"),
},
priority,
}
Expand Down
4 changes: 3 additions & 1 deletion core/store/src/genesis/state_applier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,9 @@ impl GenesisStateApplier {
set_promise_yield_receipt(state_update, &receipt);
});
}
ReceiptEnum::Data(_) | ReceiptEnum::PromiseResume(_) => {
ReceiptEnum::Data(_)
| ReceiptEnum::PromiseResume(_)
| ReceiptEnum::GlobalContractDitribution(_) => {
panic!("Expected action receipt")
}
}
Expand Down
Loading
Loading