There are a couple ways to load account data from mainnet (or devnet etc) into your localnet every time you run anchor test
.
1. Cloning
Under the hood, anchor test uses solana-test-validator
. This has an argument you can pass it called --clone
whose doc string reads as follows:
-c, --clone <ADDRESS>...
Copy an account from the cluster referenced
by the --url argument the genesis
configuration. If the ledger already exists
then this parameter is silently ignored.
You can configure your Anchor.toml
so that on every run of anchor test
, it effectively adds these flags to its internal solana-test-validator
.
2. Loading manually procured JSON data
Similar to what is described above, there is a --account
argument:
--account <ADDRESS FILENAME.JSON>...
Load an account from the provided JSON file
(see `solana account --help` on how to dump
an account to file).
Files are searched for relatively to CWD and
tests/fixtures. If the ledger already exists
then this parameter is silently ignored.
Following the solana account --help
, what you'd want to do to e.g. dump the USDC mint account from mainnet is:
$ solana -um account -o usdc_mint.json --output json EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
And there's a similar way to configure your Anchor.toml.
3. Copying Programs
You can use solana program dump
to copy a program from mainnet into a local .so
file. From there, it's a simple configuration to add that program to your localnet testing as well.
Edit: On the topic of modifying cloned account data
In a reply, OP effectively asks, "how do I modify cloned account data, for example changing an account's mint authority?"
This requires that you have some means to deserialize the data, modify it, and serialize it back into JSON data to be used with technique (2) above. This is not trivial, and the only way I've accomplished this is to write my own crate, which I've open sourced.
In response to your reply, I added an example showing explicitly how to clone and modify the USDC mint. Here's the relevant part below:
let usdc = LocalnetAccount::new_from_clone::<SplMintAccount, _>(
&pubkey!("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"),
&RpcClient::new("https://api.mainnet-beta.solana.com".to_string()),
"usdc_mint.json".to_string(),
Some(|mint: SplMintAccount| {
let mut mint = mint.clone();
mint.mint_authority = COption::Some(test_user.address.clone());
SplMintAccount::from_spl_mint(mint)
})
).unwrap();
Instead of creating entire test suites like in the example, you could write something simple that creates this LocalnetAccount
object, and just calls write_to_validator_json_file
on it.
You could also use this technique to just create token accounts with arbitrary USDC balances instead of modifying the mint.
Note that the T: AccountSerialize + AccountDeserialize
that I am using in this example is not the Anchor SPL mint directly, but my own wrapper struct (it serializes all the same). This is because Anchor SPL types have an empty impl AccountSerialize
, which by default do nothing.