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

feat: limit contract functions number #4954

Merged
merged 35 commits into from
Oct 18, 2021
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f8772eb
introduce protocol feature
Looogarithm Oct 7, 2021
d65f9fb
Merge branch 'master' into limit-functions
Looogarithm Oct 8, 2021
71d4fe3
Merge branch 'master' into limit-functions
Looogarithm Oct 8, 2021
d959bde
move validation to prepare stage
Looogarithm Oct 8, 2021
b0e754e
complete transition
Looogarithm Oct 8, 2021
646d6d6
fix default impl
Looogarithm Oct 8, 2021
4208cb2
Merge branch 'master' into limit-functions
Looogarithm Oct 8, 2021
9488564
fix callers
Looogarithm Oct 8, 2021
9d0c4fe
compilation fix
Looogarithm Oct 8, 2021
b441d17
compilation fix
Looogarithm Oct 8, 2021
965b9c9
test checking max functions
Looogarithm Oct 9, 2021
de44dbe
Merge branch 'master' into limit-functions
Longarithm Oct 9, 2021
ea87dac
implement test
Looogarithm Oct 11, 2021
b550a8c
implement test for configs
Looogarithm Oct 11, 2021
ce9643d
Merge branch 'master' into limit-functions
Longarithm Oct 11, 2021
bb450e4
Update runtime/near-vm-runner/src/preload.rs
Longarithm Oct 12, 2021
a287c78
apply suggestions
Looogarithm Oct 12, 2021
fe96a73
Merge branch 'limit-functions' of github.com:near/nearcore into limit…
Looogarithm Oct 12, 2021
5b438bb
fix config hash
Looogarithm Oct 12, 2021
90f36f2
Merge branch 'master' into limit-functions
Looogarithm Oct 12, 2021
88fba78
fix protocol feature flag
Looogarithm Oct 12, 2021
b57b444
Merge branch 'master' into limit-functions
Looogarithm Oct 14, 2021
0d7c119
apply suggestions, enable test for all protocols
Looogarithm Oct 14, 2021
45675ad
compilation fix
Looogarithm Oct 14, 2021
b0cd021
integration test for upgrading protocol version
Looogarithm Oct 15, 2021
59955ba
remove log
Looogarithm Oct 15, 2021
6b854d9
Merge branch 'master' into limit-functions
Longarithm Oct 15, 2021
3a7b470
move test
Looogarithm Oct 15, 2021
41e2e07
Merge branch 'master' into limit-functions
Longarithm Oct 15, 2021
8c3bd25
fix imports
Looogarithm Oct 15, 2021
c6c9beb
fix invalid_contracts test
Looogarithm Oct 18, 2021
fc80277
Merge branch 'master' into limit-functions
Longarithm Oct 18, 2021
0b363d3
Merge branch 'master' into limit-functions
Longarithm Oct 18, 2021
c467dd4
polish tests
Looogarithm Oct 18, 2021
53bea4f
Merge branch 'limit-functions' of github.com:near/nearcore into limit…
Looogarithm Oct 18, 2021
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.

5 changes: 5 additions & 0 deletions core/primitives-core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ pub struct VMLimitConfig {
pub max_promises_per_function_call_action: u64,
/// Max number of input data dependencies
pub max_number_input_data_dependencies: u64,
/// If present, stores max number of functions in one contract
#[serde(skip_serializing_if = "Option::is_none")]
pub max_functions_number_per_contract: Option<u64>,
}

impl Default for VMConfig {
Expand Down Expand Up @@ -118,6 +121,7 @@ impl VMConfig {
}
}

// TODO #4649: remove default impl and create impls with explicitly stated purposes
impl Default for VMLimitConfig {
fn default() -> Self {
Self {
Expand Down Expand Up @@ -162,6 +166,7 @@ impl Default for VMLimitConfig {
max_promises_per_function_call_action: 1024,
// Unlikely to hit it for normal development.
max_number_input_data_dependencies: 128,
max_functions_number_per_contract: None,
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion core/primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ protocol_feature_block_header_v3 = []
protocol_feature_alt_bn128 = ["near-primitives-core/protocol_feature_alt_bn128", "near-vm-errors/protocol_feature_alt_bn128"]
protocol_feature_chunk_only_producers = ["protocol_feature_block_header_v3"]
protocol_feature_routing_exchange_algorithm = ["near-primitives-core/protocol_feature_routing_exchange_algorithm"]
nightly_protocol_features = ["nightly_protocol", "protocol_feature_block_header_v3", "protocol_feature_alt_bn128", "protocol_feature_chunk_only_producers", "protocol_feature_routing_exchange_algorithm"]
protocol_feature_limit_contract_functions_number = []
nightly_protocol_features = ["nightly_protocol", "protocol_feature_block_header_v3", "protocol_feature_alt_bn128", "protocol_feature_chunk_only_producers", "protocol_feature_routing_exchange_algorithm", "protocol_feature_limit_contract_functions_number"]
nightly_protocol = []

[dev-dependencies]
Expand Down
4 changes: 4 additions & 0 deletions core/primitives/src/runtime/config_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ static CONFIGS: &[(ProtocolVersion, &[u8])] = &[
(0, include_config!("29.json")),
(42, include_config!("42.json")),
(48, include_config!("48.json")),
#[cfg(feature = "protocol_feature_limit_contract_functions_number")]
(123, include_config!("123.json")),
];

/// Stores runtime config for each protocol version where it was updated.
Expand Down Expand Up @@ -109,6 +111,8 @@ mod tests {
"3VBfW1GkXwKNiThPhrtjm2qGupYv5oEEZWapduXkd2gY",
"BdCfuR4Gb5qgr2nhxUgGyDHesuhZg3Az5D3sEwQdQCvC",
"2AUtULBkjrfzTepo6zFFMp4ShtiKgjpoUjoyRXLpcxiw",
#[cfg(feature = "protocol_feature_limit_contract_functions_number")]
"2NGvpASXyKxPcqJDsJNgi9U4qiRt7Bww5Q4GzLjcGT6m",
];
let actual_hashes = CONFIGS
.iter()
Expand Down
6 changes: 5 additions & 1 deletion core/primitives/src/version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ pub enum ProtocolFeature {
ChunkOnlyProducers,
#[cfg(feature = "protocol_feature_routing_exchange_algorithm")]
RoutingExchangeAlgorithm,
#[cfg(feature = "protocol_feature_limit_contract_functions_number")]
LimitContractFunctionsNumber,
Comment on lines +129 to +130
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ProtocolFeature is a natural entry point for learning about implications of a particular feature, so I think comments on enum variants here have high leverage -- you can say little, but that wouldn't require ongoing maintanence, will help other people, and could be copy-pasted into the feature stabilization PR.

}

/// Current latest stable version of the protocol.
Expand All @@ -134,7 +136,7 @@ pub const PROTOCOL_VERSION: ProtocolVersion = 48;

/// Current latest nightly version of the protocol.
#[cfg(feature = "nightly_protocol")]
pub const PROTOCOL_VERSION: ProtocolVersion = 122;
pub const PROTOCOL_VERSION: ProtocolVersion = 123;

impl ProtocolFeature {
pub const fn protocol_version(self) -> ProtocolVersion {
Expand Down Expand Up @@ -167,6 +169,8 @@ impl ProtocolFeature {
ProtocolFeature::ChunkOnlyProducers => 115,
#[cfg(feature = "protocol_feature_routing_exchange_algorithm")]
ProtocolFeature::RoutingExchangeAlgorithm => 117,
#[cfg(feature = "protocol_feature_limit_contract_functions_number")]
ProtocolFeature::LimitContractFunctionsNumber => 123,
}
}
}
Expand Down
1 change: 1 addition & 0 deletions integration-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ protocol_feature_alt_bn128 = [
]
protocol_feature_block_header_v3 = ["near-primitives/protocol_feature_block_header_v3", "near-chain/protocol_feature_block_header_v3", "near-store/protocol_feature_block_header_v3"]
protocol_feature_chunk_only_producers = ["near-client/protocol_feature_chunk_only_producers"]
protocol_feature_limit_contract_functions_number = ["near-primitives/protocol_feature_limit_contract_functions_number", "near-vm-runner/protocol_feature_limit_contract_functions_number"]
nightly_protocol_features = ["nearcore/nightly_protocol_features", "protocol_feature_alt_bn128", "protocol_feature_block_header_v3"]
nightly_protocol = ["nearcore/nightly_protocol"]
sandbox = ["near-network/sandbox", "near-chain/sandbox", "node-runtime/sandbox", "near-client/sandbox"]
110 changes: 110 additions & 0 deletions integration-tests/tests/client/process_blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ use near_primitives::errors::TxExecutionError;
use near_primitives::hash::{hash, CryptoHash};
use near_primitives::merkle::verify_hash;
use near_primitives::receipt::DelayedReceiptIndices;
use near_primitives::runtime::config_store::RuntimeConfigStore;
use near_primitives::shard_layout::ShardUId;
#[cfg(not(feature = "protocol_feature_block_header_v3"))]
use near_primitives::sharding::ShardChunkHeaderV2;
Expand All @@ -57,6 +58,8 @@ use near_primitives::types::validator_stake::ValidatorStake;
use near_primitives::types::{AccountId, BlockHeight, EpochId, NumBlocks, ProtocolVersion};
use near_primitives::utils::to_timestamp;
use near_primitives::validator_signer::{InMemoryValidatorSigner, ValidatorSigner};
#[cfg(feature = "protocol_feature_limit_contract_functions_number")]
use near_primitives::version::ProtocolFeature;
use near_primitives::version::PROTOCOL_VERSION;
use near_primitives::views::{
BlockHeaderView, FinalExecutionStatus, QueryRequest, QueryResponseKind,
Expand Down Expand Up @@ -3191,6 +3194,113 @@ fn test_validator_stake_host_function() {
}
}

// Check that we can't call a contract exceeding functions number limit after upgrade.
#[test]
fn test_limit_contract_functions_number_upgrade() {
const FUNCTIONS_NUMBER: u64 = 10_000;

#[cfg(feature = "protocol_feature_limit_contract_functions_number")]
let old_protocol_version = ProtocolFeature::LimitContractFunctionsNumber.protocol_version() - 1;
#[cfg(not(feature = "protocol_feature_limit_contract_functions_number"))]
let old_protocol_version = PROTOCOL_VERSION - 1;

let new_protocol_version = old_protocol_version + 1;

// Prepare TestEnv with a contract at the old protocol version.
let mut env = {
let epoch_length = 5;
let mut genesis =
Genesis::test(vec!["test0".parse().unwrap(), "test1".parse().unwrap()], 1);
genesis.config.epoch_length = epoch_length;
genesis.config.protocol_version = old_protocol_version;
let chain_genesis = ChainGenesis::from(&genesis);
let runtimes: Vec<Arc<dyn RuntimeAdapter>> =
vec![Arc::new(nearcore::NightshadeRuntime::test_with_runtime_config_store(
Path::new("."),
create_test_store(),
&genesis,
RuntimeConfigStore::new(None),
))];
let mut env = TestEnv::builder(chain_genesis).runtime_adapters(runtimes).build();

deploy_test_contract(
&mut env,
"test0".parse().unwrap(),
&near_test_contracts::many_functions_contract((FUNCTIONS_NUMBER + 10) as i32),
epoch_length,
1,
);
env
};

let signer = InMemorySigner::from_seed("test0".parse().unwrap(), KeyType::ED25519, "test0");
let tx = Transaction {
signer_id: "test0".parse().unwrap(),
receiver_id: "test0".parse().unwrap(),
public_key: signer.public_key(),
actions: vec![Action::FunctionCall(FunctionCallAction {
method_name: "hello0".to_string(),
args: Vec::new(),
gas: 100_000_000_000_000,
deposit: 0,
})],

nonce: 0,
block_hash: CryptoHash::default(),
};

// Run the transaction & get tx outcome.
let old_outcome = {
let tip = env.clients[0].chain.head().unwrap();
let signed_transaction =
Transaction { nonce: 10, block_hash: tip.last_block_hash, ..tx.clone() }.sign(&signer);
let tx_hash = signed_transaction.get_hash();
env.clients[0].process_tx(signed_transaction, false, false);
for i in 0..3 {
env.produce_block(0, tip.height + i + 1);
}
env.clients[0].chain.get_final_transaction_result(&tx_hash).unwrap()
};

// Move to the new protocol version.
{
let tip = env.clients[0].chain.head().unwrap();
let epoch_id = env.clients[0]
.runtime_adapter
.get_epoch_id_from_prev_block(&tip.last_block_hash)
.unwrap();
let block_producer =
env.clients[0].runtime_adapter.get_block_producer(&epoch_id, tip.height).unwrap();
let mut block = env.clients[0].produce_block(tip.height + 1).unwrap().unwrap();
set_block_protocol_version(&mut block, block_producer.clone(), new_protocol_version);
let (_, res) = env.clients[0].process_block(block.clone(), Provenance::NONE);
assert!(res.is_ok());
}

// Re-run the transaction & get tx outcome.
let new_outcome = {
let tip = env.clients[0].chain.head().unwrap();
let signed_transaction =
Transaction { nonce: 11, block_hash: tip.last_block_hash, ..tx.clone() }.sign(&signer);
let tx_hash = signed_transaction.get_hash();
env.clients[0].process_tx(signed_transaction, false, false);
for i in 0..3 {
env.produce_block(0, tip.height + i + 1);
}
env.clients[0].chain.get_final_transaction_result(&tx_hash).unwrap()
};

assert!(matches!(old_outcome.status, FinalExecutionStatus::SuccessValue(_)));
if cfg!(feature = "protocol_feature_limit_contract_functions_number") {
assert!(matches!(
new_outcome.status,
FinalExecutionStatus::Failure(TxExecutionError::ActionError(_))
));
} else {
assert!(matches!(new_outcome.status, FinalExecutionStatus::SuccessValue(_)));
}
}

mod access_key_nonce_range_tests {
use super::*;
use near_client::test_utils::create_chunk_with_transactions;
Expand Down
3 changes: 2 additions & 1 deletion nearcore/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ protocol_feature_alt_bn128 = ["near-primitives/protocol_feature_alt_bn128", "nod
protocol_feature_block_header_v3 = ["near-epoch-manager/protocol_feature_block_header_v3", "near-store/protocol_feature_block_header_v3", "near-primitives/protocol_feature_block_header_v3", "near-chain/protocol_feature_block_header_v3", "near-client/protocol_feature_block_header_v3"]
protocol_feature_chunk_only_producers = ["protocol_feature_block_header_v3", "near-chain-configs/protocol_feature_chunk_only_producers", "near-epoch-manager/protocol_feature_chunk_only_producers", "near-chain/protocol_feature_chunk_only_producers", "near-client/protocol_feature_chunk_only_producers", "node-runtime/protocol_feature_chunk_only_producers", "near-rosetta-rpc/protocol_feature_chunk_only_producers"]
protocol_feature_routing_exchange_algorithm = ["near-primitives/protocol_feature_routing_exchange_algorithm", "near-chain/protocol_feature_routing_exchange_algorithm", "near-network/protocol_feature_routing_exchange_algorithm", "near-client/protocol_feature_routing_exchange_algorithm", "near-jsonrpc/protocol_feature_routing_exchange_algorithm"]
nightly_protocol_features = ["nightly_protocol", "near-primitives/nightly_protocol_features", "near-client/nightly_protocol_features", "near-epoch-manager/nightly_protocol_features", "near-store/nightly_protocol_features", "protocol_feature_block_header_v3", "protocol_feature_alt_bn128", "protocol_feature_chunk_only_producers", "protocol_feature_routing_exchange_algorithm"]
protocol_feature_limit_contract_functions_number = ["near-primitives/protocol_feature_limit_contract_functions_number", "near-vm-runner/protocol_feature_limit_contract_functions_number"]
nightly_protocol_features = ["nightly_protocol", "near-primitives/nightly_protocol_features", "near-client/nightly_protocol_features", "near-epoch-manager/nightly_protocol_features", "near-store/nightly_protocol_features", "protocol_feature_block_header_v3", "protocol_feature_alt_bn128", "protocol_feature_chunk_only_producers", "protocol_feature_routing_exchange_algorithm", "protocol_feature_limit_contract_functions_number"]
nightly_protocol = ["near-primitives/nightly_protocol", "near-jsonrpc/nightly_protocol"]

# Force usage of a specific wasm vm irrespective of protocol version.
Expand Down
Loading