From 9a075087d0b9d1ae2af6009ebe4146537bd0d959 Mon Sep 17 00:00:00 2001 From: Pierre Date: Sat, 25 Mar 2023 05:13:18 +1100 Subject: [PATCH] feat: Add account-dir test-validator argument support (#2436) --- cli/src/config.rs | 31 +++++++++++++++++++ cli/src/lib.rs | 9 ++++-- tests/validator-clone/Anchor.toml | 6 ++++ .../accounts-snapshot/usdc-mint.json | 13 ++++++++ .../validator-clone/tests/validator-clone.ts | 9 ++++++ 5 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 tests/validator-clone/accounts-snapshot/usdc-mint.json diff --git a/cli/src/config.rs b/cli/src/config.rs index b9ed28713..7014e27b1 100644 --- a/cli/src/config.rs +++ b/cli/src/config.rs @@ -884,11 +884,20 @@ pub struct AccountEntry { pub filename: String, } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AccountDirEntry { + // Directory containing account JSON files + pub directory: String, +} + #[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct _Validator { // Load an account from the provided JSON file #[serde(skip_serializing_if = "Option::is_none")] pub account: Option>, + // Load all the accounts from the JSON files found in the specified DIRECTORY + #[serde(skip_serializing_if = "Option::is_none")] + pub account_dir: Option>, // IP address to bind the validator ports. [default: 0.0.0.0] #[serde(skip_serializing_if = "Option::is_none")] pub bind_address: Option, @@ -940,6 +949,8 @@ pub struct _Validator { pub struct Validator { #[serde(skip_serializing_if = "Option::is_none")] pub account: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub account_dir: Option>, pub bind_address: String, #[serde(skip_serializing_if = "Option::is_none")] pub clone: Option>, @@ -973,6 +984,7 @@ impl From<_Validator> for Validator { fn from(_validator: _Validator) -> Self { Self { account: _validator.account, + account_dir: _validator.account_dir, bind_address: _validator .bind_address .unwrap_or_else(|| DEFAULT_BIND_ADDRESS.to_string()), @@ -1002,6 +1014,7 @@ impl From for _Validator { fn from(validator: Validator) -> Self { Self { account: validator.account, + account_dir: validator.account_dir, bind_address: Some(validator.bind_address), clone: validator.clone, dynamic_port_range: validator.dynamic_port_range, @@ -1048,6 +1061,24 @@ impl Merge for _Validator { } }, }, + account_dir: match self.account_dir.take() { + None => other.account_dir, + Some(mut entries) => match other.account_dir { + None => Some(entries), + Some(other_entries) => { + for other_entry in other_entries { + match entries + .iter() + .position(|my_entry| *my_entry.directory == other_entry.directory) + { + None => entries.push(other_entry), + Some(i) => entries[i] = other_entry, + }; + } + Some(entries) + } + }, + }, bind_address: other.bind_address.or_else(|| self.bind_address.take()), clone: match self.clone.take() { None => other.clone, diff --git a/cli/src/lib.rs b/cli/src/lib.rs index 0340ebd5a..75475189e 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -2536,14 +2536,19 @@ fn validator_flags( flags.push(entry["address"].as_str().unwrap().to_string()); flags.push(entry["filename"].as_str().unwrap().to_string()); } + } else if key == "account_dir" { + for entry in value.as_array().unwrap() { + flags.push("--account-dir".to_string()); + flags.push(entry["directory"].as_str().unwrap().to_string()); + } } else if key == "clone" { // Client for fetching accounts data let client = if let Some(url) = entries["url"].as_str() { RpcClient::new(url.to_string()) } else { return Err(anyhow!( - "Validator url for Solana's JSON RPC should be provided in order to clone accounts from it" - )); + "Validator url for Solana's JSON RPC should be provided in order to clone accounts from it" + )); }; let mut pubkeys = value diff --git a/tests/validator-clone/Anchor.toml b/tests/validator-clone/Anchor.toml index 11a76652d..deef6b044 100644 --- a/tests/validator-clone/Anchor.toml +++ b/tests/validator-clone/Anchor.toml @@ -36,3 +36,9 @@ address = "mv3ekLzLbnVPNxjSKvqBpU3ZeZXPQdEC3bp5MDEBG68" [[test.validator.clone]] address = "8DKwAVrCEVStDYNPCsmxHtUj8LH9oXNtkVRrBfpNKvhp" + +[[test.validator.clone]] +address = "8DKwAVrCEVStDYNPCsmxHtUj8LH9oXNtkVRrBfpNKvhp" + +[[test.validator.account_dir]] +directory = "accounts-snapshot" diff --git a/tests/validator-clone/accounts-snapshot/usdc-mint.json b/tests/validator-clone/accounts-snapshot/usdc-mint.json new file mode 100644 index 000000000..46424be1b --- /dev/null +++ b/tests/validator-clone/accounts-snapshot/usdc-mint.json @@ -0,0 +1,13 @@ +{ + "pubkey": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + "account": { + "lamports": 182698617139, + "data": [ + "AQAAABzjWe1aAS4E+hQrnHUaHF6Hz9CgFhuchf/TG3jN/Nj2pIW9lUPjEQAGAQEAAAAqnl7btTwEZ5CY/3sSZRcUQ0/AjFYqmjuGEQXmctQicw==", + "base64" + ], + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "rentEpoch": 361 + } +} \ No newline at end of file diff --git a/tests/validator-clone/tests/validator-clone.ts b/tests/validator-clone/tests/validator-clone.ts index 0a2cfc387..440e271b9 100644 --- a/tests/validator-clone/tests/validator-clone.ts +++ b/tests/validator-clone/tests/validator-clone.ts @@ -67,4 +67,13 @@ describe("validator-clone", () => { assert.isNotNull(acc, "Account " + accounts[i] + " not found"); }); }); + + it("Load accounts from account-dir directory", async () => { + // USDC mint + const account = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"; + const accountInfo = await connection.getAccountInfo( + new anchor.web3.PublicKey(account) + ); + assert.isNotNull(accountInfo, "Account " + account + " not found"); + }); });