Skip to content

Commit

Permalink
feat(rpc): patch contract code/state, account/access key for sandbox …
Browse files Browse the repository at this point in the history
…node (near#4287)

* feat(rpc): patch contract code/state, account/access key for ganache node
* chain test and pytest
* poll until patch state finish in rpc

Co-authored-by: Vlad Frolov <[email protected]>
Co-authored-by: Aleksey Kladov <[email protected]>
  • Loading branch information
3 people authored Jun 14, 2021
1 parent 377908d commit 1fe28a2
Show file tree
Hide file tree
Showing 36 changed files with 516 additions and 12 deletions.
2 changes: 2 additions & 0 deletions .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ steps:
cargo-deny --all-features check bans
fi
RUSTFLAGS='-D warnings' cargo check --workspace --all-targets --all-features
# build a sandbox node should succeed
RUSTFLAGS='-D warnings' cargo check -p neard --features sandbox
python3 scripts/state/update_res.py check
python3 scripts/check_nightly.py
timeout: 30
Expand Down
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.

8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,11 @@ nightly-debug:
cargo $(RUST_OPTIONS) build -p near-vm-runner-standalone --features nightly_protocol,nightly_protocol_features
cargo $(RUST_OPTIONS) build -p state-viewer --features nearcore/nightly_protocol,nearcore/nightly_protocol_features,nearcore/performance_stats,nearcore/memory_stats
cargo $(RUST_OPTIONS) build -p store-validator --features nearcore/nightly_protocol,nearcore/nightly_protocol_features,nearcore/performance_stats,nearcore/memory_stats

sandbox:
CARGO_PROFILE_RELEASE_DEBUG=true cargo $(RUST_OPTIONS) build -p neard --features sandbox
mv target/debug/neard target/debug/near-sandbox

sandbox-release:
cargo $(RUST_OPTIONS) build -p neard --features sandbox
mv target/release/neard target/release/near-sandbox
1 change: 1 addition & 0 deletions chain/chain/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,4 @@ protocol_feature_restore_receipts_after_fix = []
protocol_feature_cap_max_gas_price = []
nightly_protocol_features = ["nightly_protocol", "protocol_feature_block_header_v3", "protocol_feature_restore_receipts_after_fix", "protocol_feature_cap_max_gas_price"]
nightly_protocol = []
sandbox = []
43 changes: 40 additions & 3 deletions chain/chain/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ use rand::seq::SliceRandom;
use rand::SeedableRng;
use tracing::{debug, error, info, warn};

#[cfg(feature = "delay_detector")]
use delay_detector::DelayDetector;
use near_chain_primitives::error::{Error, ErrorKind, LogTransientStorageError};
use near_primitives::block::{genesis_chunks, Tip};
use near_primitives::challenge::{
Expand Down Expand Up @@ -50,6 +48,8 @@ use near_primitives::views::{
};
use near_store::{ColState, ColStateHeaders, ColStateParts, ShardTries, StoreUpdate};

use near_primitives::state_record::StateRecord;

use crate::lightclient::get_epoch_block_producers_view;
use crate::migrations::check_if_block_is_first_with_chunk_of_version;
use crate::missing_chunks::{BlockLike, MissingChunksPool};
Expand All @@ -64,6 +64,8 @@ use crate::validate::{
};
use crate::{byzantine_assert, create_light_client_block_view, Doomslug};
use crate::{metrics, DoomslugThresholdMode};
#[cfg(feature = "delay_detector")]
use delay_detector::DelayDetector;

/// Maximum number of orphans chain can store.
pub const MAX_ORPHAN_SIZE: usize = 1024;
Expand Down Expand Up @@ -203,6 +205,7 @@ pub struct Chain {
/// Block economics, relevant to changes when new block must be produced.
pub block_economics_config: BlockEconomicsConfig,
pub doomslug_threshold_mode: DoomslugThresholdMode,
pending_states_to_patch: Option<Vec<StateRecord>>,
}

impl Chain {
Expand Down Expand Up @@ -239,6 +242,7 @@ impl Chain {
epoch_length: chain_genesis.epoch_length,
block_economics_config: BlockEconomicsConfig::from(chain_genesis),
doomslug_threshold_mode,
pending_states_to_patch: None,
})
}

Expand Down Expand Up @@ -353,6 +357,7 @@ impl Chain {
epoch_length: chain_genesis.epoch_length,
block_economics_config: BlockEconomicsConfig::from(chain_genesis),
doomslug_threshold_mode,
pending_states_to_patch: None,
})
}

Expand Down Expand Up @@ -1054,7 +1059,9 @@ impl Chain {
Ok((head, needs_to_start_fetching_state)) => {
chain_update.chain_store_update.save_block_height_processed(block_height);
chain_update.commit()?;


self.pending_states_to_patch = None;

if needs_to_start_fetching_state {
debug!(target: "chain", "Downloading state for block {}", block.hash());
self.start_downloading_state(me, &block)?;
Expand Down Expand Up @@ -2077,6 +2084,7 @@ impl Chain {
self.doomslug_threshold_mode,
&self.genesis,
self.transaction_validity_period,
self.pending_states_to_patch.take(),
)
}

Expand Down Expand Up @@ -2466,6 +2474,24 @@ impl Chain {
}
}

/// Sandbox node specific operations
#[cfg(feature = "sandbox")]
impl Chain {
pub fn patch_state(&mut self, records: Vec<StateRecord>) {
match self.pending_states_to_patch.take() {
None => self.pending_states_to_patch = Some(records),
Some(mut pending) => {
pending.extend_from_slice(&records);
self.pending_states_to_patch = Some(pending);
}
}
}

pub fn patch_state_in_progress(&self) -> bool {
self.pending_states_to_patch.is_some()
}
}

/// Chain update helper, contains information that is needed to process block
/// and decide to accept it or reject it.
/// If rejected nothing will be updated in underlying storage.
Expand All @@ -2481,6 +2507,7 @@ pub struct ChainUpdate<'a> {
genesis: &'a Block,
#[allow(unused)]
transaction_validity_period: BlockHeightDelta,
states_to_patch: Option<Vec<StateRecord>>,
}

impl<'a> ChainUpdate<'a> {
Expand All @@ -2494,6 +2521,7 @@ impl<'a> ChainUpdate<'a> {
doomslug_threshold_mode: DoomslugThresholdMode,
genesis: &'a Block,
transaction_validity_period: BlockHeightDelta,
states_to_patch: Option<Vec<StateRecord>>,
) -> Self {
let chain_store_update: ChainStoreUpdate<'_> = store.store_update();
ChainUpdate {
Expand All @@ -2506,6 +2534,7 @@ impl<'a> ChainUpdate<'a> {
doomslug_threshold_mode,
genesis,
transaction_validity_period,
states_to_patch,
}
}

Expand Down Expand Up @@ -2713,6 +2742,7 @@ impl<'a> ChainUpdate<'a> {
true,
true,
is_first_block_with_chunk_of_version,
None,
)
.unwrap();
let partial_state = apply_result.proof.unwrap().nodes;
Expand Down Expand Up @@ -2872,6 +2902,10 @@ impl<'a> ChainUpdate<'a> {
*block.header().random_value(),
true,
is_first_block_with_chunk_of_version,
#[cfg(feature = "sandbox")]
self.states_to_patch.take(),
#[cfg(not(feature = "sandbox"))]
None,
)
.map_err(|e| ErrorKind::Other(e.to_string()))?;

Expand Down Expand Up @@ -2928,6 +2962,7 @@ impl<'a> ChainUpdate<'a> {
*block.header().random_value(),
false,
false,
self.states_to_patch.take(),
)
.map_err(|e| ErrorKind::Other(e.to_string()))?;

Expand Down Expand Up @@ -3631,6 +3666,7 @@ impl<'a> ChainUpdate<'a> {
*block_header.random_value(),
true,
is_first_block_with_chunk_of_version,
None,
)?;

let (outcome_root, outcome_proofs) =
Expand Down Expand Up @@ -3711,6 +3747,7 @@ impl<'a> ChainUpdate<'a> {
*block_header.random_value(),
false,
false,
None,
)?;

self.chain_store_update.save_trie_changes(apply_result.trie_changes);
Expand Down
3 changes: 3 additions & 0 deletions chain/chain/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ use crate::{BlockHeader, DoomslugThresholdMode, RuntimeAdapter};
use near_chain_configs::ProtocolConfig;
#[cfg(feature = "protocol_feature_block_header_v3")]
use near_primitives::block_header::{Approval, ApprovalInner};
use near_primitives::state_record::StateRecord;

#[derive(
BorshSerialize, BorshDeserialize, Serialize, Hash, PartialEq, Eq, Ord, PartialOrd, Clone, Debug,
Expand Down Expand Up @@ -605,7 +606,9 @@ impl RuntimeAdapter for KeyValueRuntime {
generate_storage_proof: bool,
_is_new_chunk: bool,
_is_first_block_with_chunk_of_version: bool,
states_to_patch: Option<Vec<StateRecord>>,
) -> Result<ApplyTransactionResult, Error> {
assert!(states_to_patch.is_none(), "KeyValueRuntime does not support patch states.");
assert!(!generate_storage_proof);
let mut tx_results = vec![];

Expand Down
4 changes: 4 additions & 0 deletions chain/chain/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ use near_store::{PartialStorage, ShardTries, Store, StoreUpdate, Trie, WrappedTr

#[cfg(feature = "protocol_feature_block_header_v3")]
use crate::DoomslugThresholdMode;
use near_primitives::state_record::StateRecord;

#[derive(Eq, PartialEq, Debug, Clone)]
pub enum BlockStatus {
Expand Down Expand Up @@ -518,6 +519,7 @@ pub trait RuntimeAdapter: Send + Sync {
random_seed: CryptoHash,
is_new_chunk: bool,
is_first_block_with_chunk_of_version: bool,
states_to_patch: Option<Vec<StateRecord>>,
) -> Result<ApplyTransactionResult, Error> {
self.apply_transactions_with_optional_storage_proof(
shard_id,
Expand All @@ -536,6 +538,7 @@ pub trait RuntimeAdapter: Send + Sync {
false,
is_new_chunk,
is_first_block_with_chunk_of_version,
states_to_patch,
)
}

Expand All @@ -557,6 +560,7 @@ pub trait RuntimeAdapter: Send + Sync {
generate_storage_proof: bool,
is_new_chunk: bool,
is_first_block_with_chunk_of_version: bool,
states_to_patch: Option<Vec<StateRecord>>,
) -> Result<ApplyTransactionResult, Error>;

fn check_state_transition(
Expand Down
9 changes: 9 additions & 0 deletions chain/client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ near-telemetry = { path = "../telemetry" }
near-performance-metrics = { path = "../../utils/near-performance-metrics" }
near-performance-metrics-macros = { path = "../../utils/near-performance-metrics-macros" }

# Required to pass sandbox feature to node-runtime. Used in tests but cannot in dev-dependencies because
# of passing features
node-runtime = { path = "../../runtime/runtime"}

delay-detector = { path = "../../tools/delay_detector", optional = true }

[dev-dependencies]
Expand All @@ -62,3 +66,8 @@ protocol_feature_restore_receipts_after_fix = ["near-primitives/protocol_feature
protocol_feature_cap_max_gas_price = ["near-primitives/protocol_feature_cap_max_gas_price"]
nightly_protocol = ["nearcore/nightly_protocol"]
nightly_protocol_features = ["nightly_protocol", "nearcore/nightly_protocol_features", "near-chain/nightly_protocol_features", "protocol_feature_block_header_v3", "protocol_feature_add_account_versions", "protocol_feature_fix_storage_usage", "protocol_feature_restore_receipts_after_fix", "protocol_feature_cap_max_gas_price", "nearcore/protocol_feature_fix_storage_usage", "nearcore/protocol_feature_restore_receipts_after_fix"]
sandbox = ["near-network/sandbox", "near-chain/sandbox", "node-runtime/sandbox"]

[[test]]
name = "sandbox"
required-features = ["sandbox"]
18 changes: 18 additions & 0 deletions chain/client/src/client_actor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ use near_network::recorder::MetricRecorder;
#[cfg(feature = "adversarial")]
use near_network::types::NetworkAdversarialMessage;
use near_network::types::{NetworkInfo, ReasonForBan};
#[cfg(feature = "sandbox")]
use near_network::types::{NetworkSandboxMessage, SandboxResponse};
use near_network::{
NetworkAdapter, NetworkClientMessages, NetworkClientResponses, NetworkRequests,
};
Expand Down Expand Up @@ -293,6 +295,22 @@ impl Handler<NetworkClientMessages> for ClientActor {
_ => panic!("invalid adversary message"),
};
}
#[cfg(feature = "sandbox")]
NetworkClientMessages::Sandbox(sandbox_msg) => {
return match sandbox_msg {
NetworkSandboxMessage::SandboxPatchState(state) => {
self.client.chain.patch_state(state);
NetworkClientResponses::NoResponse
}
NetworkSandboxMessage::SandboxPatchStateStatus => {
NetworkClientResponses::SandboxResult(
SandboxResponse::SandboxPatchStateFinished(
!self.client.chain.patch_state_in_progress(),
),
)
}
}
}
NetworkClientMessages::Transaction { transaction, is_forwarded, check_only } => {
self.client.process_tx(transaction, is_forwarded, check_only)
}
Expand Down
25 changes: 24 additions & 1 deletion chain/client/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use near_primitives::types::{
};
use near_primitives::validator_signer::{InMemoryValidatorSigner, ValidatorSigner};
use near_primitives::version::PROTOCOL_VERSION;
use near_primitives::views::{AccountView, QueryRequest, QueryResponseKind};
use near_primitives::views::{AccountView, QueryRequest, QueryResponseKind, StateItem};
use near_store::test_utils::create_test_store;
use near_store::Store;
use near_telemetry::TelemetryActor;
Expand Down Expand Up @@ -1135,6 +1135,29 @@ impl TestEnv {
}
}

pub fn query_state(&mut self, account_id: AccountId) -> Vec<StateItem> {
let head = self.clients[0].chain.head().unwrap();
let last_block = self.clients[0].chain.get_block(&head.last_block_hash).unwrap().clone();
let last_chunk_header = &last_block.chunks()[0];
let response = self.clients[0]
.runtime_adapter
.query(
0,
&last_chunk_header.prev_state_root(),
last_block.header().height(),
last_block.header().raw_timestamp(),
last_block.header().prev_hash(),
last_block.header().hash(),
last_block.header().epoch_id(),
&QueryRequest::ViewState { account_id, prefix: vec![].into() },
)
.unwrap();
match response.kind {
QueryResponseKind::ViewState(view_state_result) => view_state_result.values,
_ => panic!("Wrong return value"),
}
}

pub fn query_balance(&mut self, account_id: AccountId) -> Balance {
self.query_account(account_id).amount
}
Expand Down
1 change: 1 addition & 0 deletions chain/client/tests/challenges.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ fn test_verify_chunk_invalid_state_challenge() {
DoomslugThresholdMode::NoApprovals,
&genesis_block,
transaction_validity_period,
None,
);

chain_update.create_chunk_state_challenge(&last_block, &block, &block.chunks()[0]).unwrap()
Expand Down
Loading

0 comments on commit 1fe28a2

Please sign in to comment.