Browse Source

feat: Add account-dir test-validator argument support (#2436)

Pierre 2 years ago
parent
commit
9a075087d0

+ 31 - 0
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<Vec<AccountEntry>>,
+    // Load all the accounts from the JSON files found in the specified DIRECTORY
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub account_dir: Option<Vec<AccountDirEntry>>,
     // IP address to bind the validator ports. [default: 0.0.0.0]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub bind_address: Option<String>,
@@ -940,6 +949,8 @@ pub struct _Validator {
 pub struct Validator {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub account: Option<Vec<AccountEntry>>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub account_dir: Option<Vec<AccountDirEntry>>,
     pub bind_address: String,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub clone: Option<Vec<CloneEntry>>,
@@ -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<Validator> 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,

+ 7 - 2
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

+ 6 - 0
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"

+ 13 - 0
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
+  }
+}

+ 9 - 0
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");
+  });
 });