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

Cap maximum gas price #4308

Merged
merged 10 commits into from
May 24, 2021
Merged
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
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ metric_recorder = ["neard/metric_recorder"]
delay_detector = ["neard/delay_detector"]
rosetta_rpc = ["neard/rosetta_rpc"]
nightly_protocol = ["near-primitives/nightly_protocol", "near-jsonrpc/nightly_protocol", "testlib/nightly_protocol", "neard/nightly_protocol"]
nightly_protocol_features = ["nightly_protocol", "neard/nightly_protocol_features", "protocol_feature_evm", "protocol_feature_block_header_v3", "protocol_feature_alt_bn128", "protocol_feature_add_account_versions", "protocol_feature_tx_size_limit", "protocol_feature_allow_create_account_on_delete", "testlib/nightly_protocol_features", "protocol_feature_fix_storage_usage", "protocol_feature_restore_receipts_after_fix"]
nightly_protocol_features = ["nightly_protocol", "neard/nightly_protocol_features", "protocol_feature_evm", "protocol_feature_block_header_v3", "protocol_feature_alt_bn128", "protocol_feature_add_account_versions", "protocol_feature_tx_size_limit", "protocol_feature_allow_create_account_on_delete", "testlib/nightly_protocol_features", "protocol_feature_fix_storage_usage", "protocol_feature_restore_receipts_after_fix", "protocol_feature_cap_max_gas_price"]
protocol_feature_evm = ["neard/protocol_feature_evm", "testlib/protocol_feature_evm", "runtime-params-estimator/protocol_feature_evm"]
protocol_feature_alt_bn128 = ["neard/protocol_feature_alt_bn128", "testlib/protocol_feature_alt_bn128", "runtime-params-estimator/protocol_feature_alt_bn128"]
protocol_feature_block_header_v3 = ["near-primitives/protocol_feature_block_header_v3", "near-chain/protocol_feature_block_header_v3", "neard/protocol_feature_block_header_v3"]
Expand All @@ -124,6 +124,7 @@ protocol_feature_allow_create_account_on_delete = ["testlib/protocol_feature_all
protocol_feature_add_account_versions = ["near-primitives/protocol_feature_add_account_versions"]
protocol_feature_fix_storage_usage = ["near-primitives/protocol_feature_fix_storage_usage", "neard/protocol_feature_fix_storage_usage", "node-runtime/protocol_feature_fix_storage_usage"]
protocol_feature_restore_receipts_after_fix = ["near-primitives/protocol_feature_restore_receipts_after_fix", "near-chain/protocol_feature_restore_receipts_after_fix", "neard/protocol_feature_restore_receipts_after_fix", "node-runtime/protocol_feature_restore_receipts_after_fix", "restored-receipts-verifier/protocol_feature_restore_receipts_after_fix"]
protocol_feature_cap_max_gas_price = ["near-primitives/protocol_feature_cap_max_gas_price", "neard/protocol_feature_cap_max_gas_price", "near-chain/protocol_feature_cap_max_gas_price"]

# enable this to build neard with wasmer 1.0 runner
# now if none of wasmer0_default, wasmer1_default or wasmtime_default is enabled, wasmer0 would be default
Expand Down
3 changes: 2 additions & 1 deletion chain/chain/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,6 @@ no_cache = ["near-store/no_cache"]
protocol_feature_evm = ["near-primitives/protocol_feature_evm", "near-chain-configs/protocol_feature_evm"]
protocol_feature_block_header_v3 = []
protocol_feature_restore_receipts_after_fix = []
nightly_protocol_features = ["nightly_protocol", "protocol_feature_block_header_v3", "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 = []
10 changes: 8 additions & 2 deletions chain/chain/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use near_crypto::Signature;
use near_pool::types::PoolIterator;
pub use near_primitives::block::{Block, BlockHeader, Tip};
use near_primitives::challenge::{ChallengesResult, SlashedValidator};
use near_primitives::checked_feature;
use near_primitives::epoch_manager::block_info::BlockInfo;
use near_primitives::epoch_manager::epoch_info::EpochInfo;
use near_primitives::errors::InvalidTxError;
Expand Down Expand Up @@ -167,8 +168,13 @@ impl BlockEconomicsConfig {
}
}

pub fn max_gas_price(&self, _protocol_version: ProtocolVersion) -> Balance {
self.max_gas_price
pub fn max_gas_price(&self, protocol_version: ProtocolVersion) -> Balance {
if checked_feature!("protocol_feature_cap_max_gas_price", CapMaxGasPrice, protocol_version)
{
std::cmp::min(self.max_gas_price, 10 * self.min_gas_price(protocol_version))
} else {
self.max_gas_price
}
}

pub fn gas_price_adjustment_rate(&self, _protocol_version: ProtocolVersion) -> Rational {
Expand Down
3 changes: 2 additions & 1 deletion chain/client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,6 @@ protocol_feature_block_header_v3 = ["near-primitives/protocol_feature_block_head
protocol_feature_add_account_versions = ["near-primitives/protocol_feature_add_account_versions"]
protocol_feature_fix_storage_usage = ["near-primitives/protocol_feature_fix_storage_usage"]
protocol_feature_restore_receipts_after_fix = []
protocol_feature_cap_max_gas_price = ["near-primitives/protocol_feature_cap_max_gas_price"]
nightly_protocol = []
nightly_protocol_features = ["nightly_protocol", "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"]
nightly_protocol_features = ["nightly_protocol", "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"]
43 changes: 41 additions & 2 deletions chain/client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1671,6 +1671,8 @@ mod test {

use cached::Cached;

#[cfg(feature = "protocol_feature_cap_max_gas_price")]
use near_chain::Provenance;
use near_chain::{ChainGenesis, RuntimeAdapter};
use near_chain_configs::Genesis;
use near_chunks::test_utils::ChunkForwardingTestFixture;
Expand All @@ -1679,6 +1681,8 @@ mod test {
use near_primitives::block::{Approval, ApprovalInner};
use near_primitives::hash::hash;
use near_primitives::validator_signer::InMemoryValidatorSigner;
#[cfg(feature = "protocol_feature_cap_max_gas_price")]
use near_primitives::version::ProtocolFeature;
use near_primitives::version::PROTOCOL_VERSION;
use near_store::test_utils::create_test_store;
use neard::config::GenesisExt;
Expand All @@ -1693,8 +1697,7 @@ mod test {
use near_primitives::sharding::{PartialEncodedChunk, ShardChunkHeader};
use near_primitives::utils::MaybeValidated;

fn create_runtimes(n: usize) -> Vec<Arc<dyn RuntimeAdapter>> {
let genesis = Genesis::test(vec!["test0", "test1"], 1);
pub fn create_nightshade_runtimes(genesis: &Genesis, n: usize) -> Vec<Arc<dyn RuntimeAdapter>> {
(0..n)
.map(|_| {
Arc::new(neard::NightshadeRuntime::new(
Expand All @@ -1709,6 +1712,11 @@ mod test {
.collect()
}

fn create_runtimes(n: usize) -> Vec<Arc<dyn RuntimeAdapter>> {
let genesis = Genesis::test(vec!["test0", "test1"], 1);
create_nightshade_runtimes(&genesis, n)
}

#[test]
fn test_pending_approvals() {
let runtimes = create_runtimes(1);
Expand Down Expand Up @@ -1754,6 +1762,37 @@ mod test {
assert_eq!(env.clients[0].pending_approvals.cache_size(), 0);
}

#[cfg(feature = "protocol_feature_cap_max_gas_price")]
#[test]
fn test_cap_max_gas_price() {
let mut genesis = Genesis::test(vec!["test0", "test1"], 1);
let epoch_length = 5;
genesis.config.min_gas_price = 1_000;
genesis.config.max_gas_price = 1_000_000;
genesis.config.protocol_version = ProtocolFeature::CapMaxGasPrice.protocol_version();
genesis.config.epoch_length = epoch_length;
let chain_genesis = ChainGenesis::from(&genesis);
let runtimes = create_nightshade_runtimes(&genesis, 1);
let mut env = TestEnv::new_with_runtime(chain_genesis, 1, 1, runtimes);

for i in 1..epoch_length {
let block = env.clients[0].produce_block(i).unwrap().unwrap();
env.process_block(0, block, Provenance::PRODUCED);
}

let last_block =
env.clients[0].chain.get_block_by_height(epoch_length - 1).unwrap().clone();
let protocol_version = env.clients[0]
.runtime_adapter
.get_epoch_protocol_version(last_block.header().epoch_id())
.unwrap();
let min_gas_price =
env.clients[0].chain.block_economics_config.min_gas_price(protocol_version);
let max_gas_price =
env.clients[0].chain.block_economics_config.max_gas_price(protocol_version);
assert!(max_gas_price <= 10 * min_gas_price);
}

#[test]
fn test_process_partial_encoded_chunk_with_missing_block() {
let runtimes = create_runtimes(1);
Expand Down
179 changes: 118 additions & 61 deletions chain/client/tests/process_blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ use near_primitives::transaction::{
};
use near_primitives::trie_key::TrieKey;
use near_primitives::types::validator_stake::ValidatorStake;
use near_primitives::types::{AccountId, BlockHeight, EpochId, NumBlocks};
use near_primitives::types::{AccountId, BlockHeight, EpochId, NumBlocks, ProtocolVersion};
use near_primitives::utils::to_timestamp;
use near_primitives::validator_signer::{InMemoryValidatorSigner, ValidatorSigner};
use near_primitives::version::PROTOCOL_VERSION;
Expand Down Expand Up @@ -79,6 +79,79 @@ pub fn create_nightshade_runtimes(genesis: &Genesis, n: usize) -> Vec<Arc<dyn Ru
.collect()
}

/// Create environment and set of transactions which cause congestion on the chain.
fn prepare_env_with_congestion(
protocol_version: ProtocolVersion,
gas_price_adjustment_rate: Option<Rational>,
number_of_transactions: u64,
) -> (TestEnv, Vec<CryptoHash>) {
init_test_logger();
let epoch_length = 100;
let mut genesis = Genesis::test(vec!["test0", "test1"], 1);
genesis.config.protocol_version = protocol_version;
genesis.config.epoch_length = epoch_length;
genesis.config.gas_limit = 10_000_000_000_000;
if let Some(gas_price_adjustment_rate) = gas_price_adjustment_rate {
genesis.config.gas_price_adjustment_rate = gas_price_adjustment_rate;
}
let chain_genesis = ChainGenesis::from(&genesis);
let mut env =
TestEnv::new_with_runtime(chain_genesis, 1, 1, create_nightshade_runtimes(&genesis, 1));
let genesis_block = env.clients[0].chain.get_block_by_height(0).unwrap().clone();
let signer = InMemorySigner::from_seed("test0", KeyType::ED25519, "test0");

// Deploy contract to test0.
let tx = SignedTransaction::from_actions(
1,
"test0".to_string(),
"test0".to_string(),
&signer,
vec![Action::DeployContract(DeployContractAction {
code: near_test_contracts::rs_contract().to_vec(),
})],
*genesis_block.hash(),
);
env.clients[0].process_tx(tx, false, false);
for i in 1..3 {
env.produce_block(0, i);
}

// Create function call transactions that generate promises.
let gas_1 = 9_000_000_000_000;
let gas_2 = gas_1 / 3;
let mut tx_hashes = vec![];

for i in 0..number_of_transactions {
let data = serde_json::json!([
{"create": {
"account_id": "test0",
"method_name": "call_promise",
"arguments": [],
"amount": "0",
"gas": gas_2,
}, "id": 0 }
]);

let signed_transaction = SignedTransaction::from_actions(
i + 10,
"test0".to_string(),
"test0".to_string(),
&signer,
vec![Action::FunctionCall(FunctionCallAction {
method_name: "call_promise".to_string(),
args: serde_json::to_vec(&data).unwrap(),
gas: gas_1,
deposit: 0,
})],
*genesis_block.hash(),
);
tx_hashes.push(signed_transaction.get_hash());
env.clients[0].process_tx(signed_transaction, false, false);
}

(env, tx_hashes)
}

/// Runs block producing client and stops after network mock received two blocks.
#[test]
fn produce_two_blocks() {
Expand Down Expand Up @@ -2646,67 +2719,9 @@ fn set_no_chunk_in_block(block: &mut Block, prev_block: &Block) {

#[test]
fn test_congestion_receipt_execution() {
init_test_logger();
let epoch_length = 100;
let mut genesis = Genesis::test(vec!["test0", "test1"], 1);
genesis.config.epoch_length = epoch_length;
genesis.config.gas_limit = 10000000000000;
let chain_genesis = ChainGenesis::from(&genesis);
let mut env =
TestEnv::new_with_runtime(chain_genesis, 1, 1, create_nightshade_runtimes(&genesis, 1));
let genesis_block = env.clients[0].chain.get_block_by_height(0).unwrap().clone();
let signer = InMemorySigner::from_seed("test0", KeyType::ED25519, "test0");
let (mut env, tx_hashes) = prepare_env_with_congestion(PROTOCOL_VERSION, None, 3);

// step 0: deploy contract to test0
let tx = SignedTransaction::from_actions(
1,
"test0".to_string(),
"test0".to_string(),
&signer,
vec![Action::DeployContract(DeployContractAction {
code: near_test_contracts::rs_contract().to_vec(),
})],
*genesis_block.hash(),
);
env.clients[0].process_tx(tx, false, false);
for i in 1..3 {
env.produce_block(0, i);
}

// step 1: create function call transactions that generate promises
let gas_1 = 9_000_000_000_000;
let gas_2 = gas_1 / 3;
let mut tx_hashes = vec![];

for i in 0..3 {
let data = serde_json::json!([
{"create": {
"account_id": "test0",
"method_name": "call_promise",
"arguments": [],
"amount": "0",
"gas": gas_2,
}, "id": 0 }
]);

let signed_transaction = SignedTransaction::from_actions(
i + 10,
"test0".to_string(),
"test0".to_string(),
&signer,
vec![Action::FunctionCall(FunctionCallAction {
method_name: "call_promise".to_string(),
args: serde_json::to_vec(&data).unwrap(),
gas: gas_1,
deposit: 0,
})],
*genesis_block.hash(),
);
tx_hashes.push(signed_transaction.get_hash());
env.clients[0].process_tx(signed_transaction, false, false);
}

// step 2: produce block with no new chunk
// Produce block with no new chunk.
env.produce_block(0, 3);
let height = 4;
env.produce_block(0, height);
Expand Down Expand Up @@ -3119,3 +3134,45 @@ mod storage_usage_fix_tests {
);
}
}

#[cfg(feature = "protocol_feature_cap_max_gas_price")]
#[cfg(test)]
mod cap_max_gas_price_tests {
use super::*;
use near_primitives::version::ProtocolFeature;

fn does_gas_price_exceed_limit(protocol_version: ProtocolVersion) -> bool {
let mut env =
prepare_env_with_congestion(protocol_version, Some(Rational::new_raw(2, 1)), 7).0;
let mut was_congested = false;
let mut price_exceeded_limit = false;

for i in 3..20 {
env.produce_block(0, i);
let block = env.clients[0].chain.get_block_by_height(i).unwrap().clone();
let protocol_version = env.clients[0]
.runtime_adapter
.get_epoch_protocol_version(block.header().epoch_id())
.unwrap();
let min_gas_price =
env.clients[0].chain.block_economics_config.min_gas_price(protocol_version);
was_congested |= block.chunks()[0].gas_used() >= block.chunks()[0].gas_limit();
price_exceeded_limit |= block.header().gas_price() > 10 * min_gas_price;
}

assert!(was_congested);
price_exceeded_limit
}

#[test]
fn test_not_capped_gas_price() {
assert!(does_gas_price_exceed_limit(
ProtocolFeature::CapMaxGasPrice.protocol_version() - 1
));
}

#[test]
fn test_capped_gas_price() {
assert!(!does_gas_price_exceed_limit(ProtocolFeature::CapMaxGasPrice.protocol_version()));
}
}
3 changes: 2 additions & 1 deletion core/primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ protocol_feature_tx_size_limit = ["near-primitives-core/protocol_feature_tx_size
protocol_feature_allow_create_account_on_delete = []
protocol_feature_fix_storage_usage = []
protocol_feature_restore_receipts_after_fix = []
nightly_protocol_features = ["nightly_protocol", "protocol_feature_evm", "protocol_feature_block_header_v3", "protocol_feature_alt_bn128", "protocol_feature_add_account_versions", "protocol_feature_tx_size_limit", "protocol_feature_allow_create_account_on_delete", "protocol_feature_fix_storage_usage", "protocol_feature_restore_receipts_after_fix"]
protocol_feature_cap_max_gas_price = []
nightly_protocol_features = ["nightly_protocol", "protocol_feature_evm", "protocol_feature_block_header_v3", "protocol_feature_alt_bn128", "protocol_feature_add_account_versions", "protocol_feature_tx_size_limit", "protocol_feature_allow_create_account_on_delete", "protocol_feature_fix_storage_usage", "protocol_feature_restore_receipts_after_fix", "protocol_feature_cap_max_gas_price"]
nightly_protocol = []


Expand Down
4 changes: 4 additions & 0 deletions core/primitives/src/version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ pub enum ProtocolFeature {
FixStorageUsage,
#[cfg(feature = "protocol_feature_restore_receipts_after_fix")]
RestoreReceiptsAfterFix,
#[cfg(feature = "protocol_feature_cap_max_gas_price")]
CapMaxGasPrice,
}

/// Current latest stable version of the protocol.
Expand Down Expand Up @@ -145,6 +147,8 @@ impl ProtocolFeature {
ProtocolFeature::FixStorageUsage => 111,
#[cfg(feature = "protocol_feature_restore_receipts_after_fix")]
ProtocolFeature::RestoreReceiptsAfterFix => 112,
#[cfg(feature = "protocol_feature_cap_max_gas_price")]
ProtocolFeature::CapMaxGasPrice => 113,
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion neard/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ protocol_feature_tx_size_limit = ["near-primitives/protocol_feature_tx_size_limi
protocol_feature_allow_create_account_on_delete = ["node-runtime/protocol_feature_allow_create_account_on_delete"]
protocol_feature_fix_storage_usage = ["near-primitives/protocol_feature_fix_storage_usage", "node-runtime/protocol_feature_fix_storage_usage"]
protocol_feature_restore_receipts_after_fix = ["near-primitives/protocol_feature_restore_receipts_after_fix"]
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_evm", "protocol_feature_block_header_v3", "protocol_feature_alt_bn128", "protocol_feature_add_account_versions", "protocol_feature_tx_size_limit", "protocol_feature_allow_create_account_on_delete", "protocol_feature_fix_storage_usage", "protocol_feature_restore_receipts_after_fix"]
protocol_feature_cap_max_gas_price = ["near-primitives/protocol_feature_cap_max_gas_price", "near-chain/protocol_feature_cap_max_gas_price"]
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_evm", "protocol_feature_block_header_v3", "protocol_feature_alt_bn128", "protocol_feature_add_account_versions", "protocol_feature_tx_size_limit", "protocol_feature_allow_create_account_on_delete", "protocol_feature_fix_storage_usage", "protocol_feature_restore_receipts_after_fix", "protocol_feature_cap_max_gas_price"]
nightly_protocol = ["near-primitives/nightly_protocol", "near-jsonrpc/nightly_protocol"]

[[bin]]
Expand Down