Skip to content

Commit

Permalink
pytest: fix nayduck looking for contracts that are long long gone (#1…
Browse files Browse the repository at this point in the history
…2748)

Although not an ideal solution, this is introducing a
near-test-contracts binary that can output the contracts upon request. A
good solution would be for pytest to either maintain their own contracts
or link to `near-test-contracts` proper and grab the contracts by
calling a function, just like is done in the rest of the test suite.

If neard is known to be always built with e.g. `test_features` for
nayduck specifically, this code could be moved to a top-level neard
subcommand.

---------

Co-authored-by: wacban <[email protected]>
Co-authored-by: Waclaw Banasik <[email protected]>
  • Loading branch information
3 people authored Jan 31, 2025
1 parent 33b4907 commit 49b24de
Show file tree
Hide file tree
Showing 13 changed files with 130 additions and 28 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ near-telemetry = { path = "chain/telemetry" }
near-test-contracts = { path = "runtime/near-test-contracts" }
near-time = { path = "core/time" }
near-undo-block = { path = "tools/undo-block" }
near-dump-test-contract = { path = "tools/dump-test-contract" }
near-vm-test-api = { path = "runtime/near-vm/test-api" }
near-vm-compiler = { path = "runtime/near-vm/compiler" }
near-vm-compiler-singlepass = { path = "runtime/near-vm/compiler-singlepass" }
Expand Down
6 changes: 5 additions & 1 deletion neard/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ near-state-parts-dump-check.workspace = true
near-state-viewer.workspace = true
near-store.workspace = true
near-undo-block.workspace = true
near-dump-test-contract.workspace = true

[build-dependencies]
anyhow.workspace = true
Expand All @@ -66,7 +67,10 @@ default = ["json_rpc", "rosetta_rpc"]

performance_stats = ["nearcore/performance_stats"]
c_memory_stats = ["nearcore/c_memory_stats"]
test_features = ["nearcore/test_features"]
test_features = [
"nearcore/test_features",
"near-dump-test-contract/test_features",
]
expensive_tests = ["nearcore/expensive_tests"]
rosetta_rpc = ["nearcore/rosetta_rpc"]
json_rpc = ["nearcore/json_rpc"]
Expand Down
7 changes: 7 additions & 0 deletions neard/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use near_client::ConfigUpdater;
use near_cold_store_tool::ColdStoreCommand;
use near_config_utils::DownloadConfigType;
use near_database_tool::commands::DatabaseCommand;
use near_dump_test_contract::DumpTestContractCommand;
use near_dyn_configs::{UpdatableConfigLoader, UpdatableConfigLoaderError, UpdatableConfigs};
use near_flat_storage::commands::FlatStorageCommand;
use near_fork_network::cli::ForkNetworkCommand;
Expand Down Expand Up @@ -147,6 +148,9 @@ impl NeardCmd {
NeardSubCommand::ReplayArchive(cmd) => {
cmd.run(&home_dir, genesis_validation)?;
}
NeardSubCommand::DumpTestContracts(cmd) => {
cmd.run()?;
}
};
Ok(())
}
Expand Down Expand Up @@ -253,6 +257,9 @@ pub(super) enum NeardSubCommand {

/// Replays the blocks in the chain from an archival node.
ReplayArchive(ReplayArchiveCommand),

/// Placeholder for test contracts subcommand
DumpTestContracts(DumpTestContractCommand),
}

#[allow(unused)]
Expand Down
2 changes: 1 addition & 1 deletion pytest/lib/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -875,14 +875,14 @@ def init_cluster(
is_local = config['local']
near_root = config['near_root']
binary_name = config.get('binary_name', 'neard')
binary_path = os.path.join(near_root, binary_name)

if extra_state_dumper:
num_observers += 1

logger.info("Creating %s cluster configuration with %s nodes" %
("LOCAL" if is_local else "REMOTE", num_nodes + num_observers))

binary_path = os.path.join(near_root, binary_name)
process = subprocess.Popen(
[
binary_path,
Expand Down
28 changes: 17 additions & 11 deletions pytest/lib/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@
import time
import typing
import requests
import subprocess
from prometheus_client.parser import text_string_to_metric_families
from retrying import retry
from rc import gcloud

import cluster
import transaction
from branches import _REPO_DIR

from configured_logger import logger


Expand Down Expand Up @@ -125,7 +128,7 @@ def count(self, pattern: str) -> int:

class MetricsTracker:
"""Helper class to collect prometheus metrics from the node.
Usage:
tracker = MetricsTracker(node)
assert tracker.get_int_metric_value("near-connections") == 2
Expand Down Expand Up @@ -242,16 +245,19 @@ def load_binary_file(filepath):


def load_test_contract(
filename: str = 'backwards_compatible_rs_contract.wasm') -> bytearray:
"""Loads a WASM file from near-test-contracts package.
This is just a convenience function around load_binary_file which loads
files from ../runtime/near-test-contracts/res directory. By default
test_contract_rs.wasm is loaded.
"""
repo_dir = pathlib.Path(__file__).resolve().parents[2]
path = repo_dir / 'runtime/near-test-contracts/res' / filename
return load_binary_file(path)
filename: str = 'backwards_compatible_rs_contract.wasm',
config: cluster.Config = cluster.DEFAULT_CONFIG,
) -> bytearray:
"""Loads a WASM file from neard."""

near_root = config['near_root']
binary_name = config.get('binary_name', 'neard')
binary_path = os.path.join(near_root, binary_name)

logger.info(f'Loading test contract {filename}')
cmd = [binary_path, 'dump-test-contracts', '--contract-name', filename]
output = subprocess.check_output(cmd)
return output


def user_name():
Expand Down
10 changes: 6 additions & 4 deletions pytest/tests/sanity/backward_compatible.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,15 @@ def main():
block_height = stable_node.get_latest_block().height
nonce = block_height * 1_000_000 - 1

tx = sign_deploy_contract_tx(new_signer_key, utils.load_test_contract(),
nonce, block_hash)
test_contract = utils.load_test_contract(
config=executables.current.node_config())
tx = sign_deploy_contract_tx(new_signer_key, test_contract, nonce,
block_hash)
res = stable_node.send_tx_and_wait(tx, timeout=20)
assert 'error' not in res, res

tx = sign_deploy_contract_tx(stable_node.signer_key,
utils.load_test_contract(), 3, block_hash)
tx = sign_deploy_contract_tx(stable_node.signer_key, test_contract, 3,
block_hash)
res = stable_node.send_tx_and_wait(tx, timeout=20)
assert 'error' not in res, res

Expand Down
8 changes: 4 additions & 4 deletions pytest/tests/sanity/congestion_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
class CongestionControlTest(unittest.TestCase):

def setUp(self):
self.config = load_config()
self.threads = []

def tearDown(self):
Expand Down Expand Up @@ -265,7 +266,6 @@ def __load(self, node: BaseNode, sender_account: Key, target_account: Key):
def __setup_node(self) -> BaseNode:
logger.info("Setting up the node")
epoch_length = 100
config = load_config()
genesis_config_changes = [
("epoch_length", epoch_length),
("shard_layout", SHARD_LAYOUT),
Expand All @@ -285,12 +285,12 @@ def __setup_node(self) -> BaseNode:
num_nodes=1,
num_observers=0,
num_shards=NUM_SHARDS,
config=config,
config=self.config,
genesis_config_changes=genesis_config_changes,
client_config_changes=client_config_changes,
)

node = spin_up_node(config, near_root, node_dir, 0)
node = spin_up_node(self.config, near_root, node_dir, 0)

# Save a block hash to use for creating transactions. Querying it every
# time when creating a new transaction is really slow.
Expand Down Expand Up @@ -325,7 +325,7 @@ def __create_accounts(self, node: BaseNode, accounts: list[Key]):
def __deploy_contracts(self, node: BaseNode, accounts: list[Key]):
logger.info("Deploying contracts")

contract = load_test_contract('test_contract_rs.wasm')
contract = load_test_contract('rs_contract.wasm', self.config)
deploy_contract_tx_list = list()
for account in accounts:
tx_hash = self.__deploy_contract(node, account, contract)
Expand Down
8 changes: 4 additions & 4 deletions pytest/tests/sanity/db_migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@
}


def deploy_contract(node):
def deploy_contract(node, config):
hash_ = node.get_latest_block().hash_bytes
tx = sign_deploy_contract_tx(node.signer_key, utils.load_test_contract(),
10, hash_)
test_contract = utils.load_test_contract(config=config)
tx = sign_deploy_contract_tx(node.signer_key, test_contract, 10, hash_)
node.send_tx_and_wait(tx, timeout=15)
utils.wait_for_blocks(node, count=3)

Expand Down Expand Up @@ -113,7 +113,7 @@ def main():
logging.info("Running the stable node...")
utils.wait_for_blocks(node, count=EPOCH_LENGTH)
logging.info("Blocks are being produced, sending some tx...")
deploy_contract(node)
deploy_contract(node, executables.current.node_config())
send_some_tx(node)
unstake_and_stake(nodes[1], node)

Expand Down
2 changes: 1 addition & 1 deletion pytest/tests/sanity/slow_chunk.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def __deploy_contract(self, node):
logger.info("Deploying contract.")

block_hash = node.get_latest_block().hash_bytes
contract = load_test_contract('test_contract_rs.wasm')
contract = load_test_contract('rs_contract.wasm')

tx = sign_deploy_contract_tx(node.signer_key, contract, 10, block_hash)
node.send_tx(tx)
Expand Down
4 changes: 2 additions & 2 deletions pytest/tests/sanity/upgradable.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,8 @@ def test_upgrade() -> None:

# deploy a contract
hash = nodes[0].get_latest_block().hash_bytes
tx = sign_deploy_contract_tx(nodes[0].signer_key,
utils.load_test_contract(), 1, hash)
test_contract = utils.load_test_contract(config=config)
tx = sign_deploy_contract_tx(nodes[0].signer_key, test_contract, 1, hash)
res = nodes[0].send_tx_and_wait(tx, timeout=20)
assert 'error' not in res, res

Expand Down
28 changes: 28 additions & 0 deletions tools/dump-test-contract/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[package]
name = "near-dump-test-contract"
version.workspace = true
authors.workspace = true
edition.workspace = true
rust-version.workspace = true
repository.workspace = true
license.workspace = true
publish = false

[lints]
workspace = true

[dependencies]
anyhow.workspace = true
clap.workspace = true

near-test-contracts.workspace = true

[features]
nightly_protocol = []
nightly = [
"near-test-contracts/nightly",
"nightly_protocol",
]
test_features = [
"near-test-contracts/test_features",
]
44 changes: 44 additions & 0 deletions tools/dump-test-contract/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use std::io::Write;

use clap::Parser;
use near_test_contracts::{
backwards_compatible_rs_contract, congestion_control_test_contract, estimator_contract,
ft_contract, fuzzing_contract, nightly_rs_contract, rs_contract, smallest_rs_contract,
trivial_contract, ts_contract,
};

#[derive(Parser)]
pub struct DumpTestContractCommand {
#[arg(short, long)]
contract_name: String,
}

impl DumpTestContractCommand {
pub fn run(&self) -> anyhow::Result<()> {
let Some((name, extension)) = self.contract_name.rsplit_once(".") else {
panic!("argument expected in `filename.wasm` form");
};

if extension != "wasm" {
panic!("unsupported filetype `{extension}`");
}

let code = match &*name {
"trivial" => trivial_contract(),
"rs_contract" => rs_contract(),
"nightly_rs_contract" => nightly_rs_contract(),
"backwards_compatible_rs_contract" => backwards_compatible_rs_contract(),
"ts_contract" => ts_contract(),
"fuzzing_contract" => fuzzing_contract(),
"ft_contract" => ft_contract(),
"smallest_rs_contract" => smallest_rs_contract(),
"estimator_contract" => estimator_contract(),
"congestion_control_test_contract" => congestion_control_test_contract(),
_ => panic!("unknown contract {name}"),
};

std::io::stdout().write_all(&code).expect("while writing code to stdout");

Ok(())
}
}

0 comments on commit 49b24de

Please sign in to comment.