cli: Add `anchor keys sync` command (#2505)

This commit is contained in:
acheron 2023-05-28 22:34:53 +02:00 committed by GitHub
parent 0c8498d195
commit 70d922301e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 99 additions and 6 deletions

View File

@ -18,6 +18,7 @@ The minor version will be incremented upon a breaking change and the patch versi
- bench: Add benchmarking for compute units usage ([#2466](https://github.com/coral-xyz/anchor/pull/2466))
- cli: `idl set-buffer`, `idl set-authority` and `idl close` take an option `--print-only`. which prints transaction in a base64 Borsh compatible format but not sent to the cluster. It's helpful when managing authority under a multisig, e.g., a user can create a proposal for a `Custom Instruction` in SPL Governance ([#2486](https://github.com/coral-xyz/anchor/pull/2486)).
- lang: Add `emit_cpi!` and `#[event_cpi]` macros(behind `event-cpi` feature flag) to store event logs in transaction metadata ([#2438](https://github.com/coral-xyz/anchor/pull/2438)).
- cli: Add `keys sync` command to sync program id declarations ([#2505](https://github.com/coral-xyz/anchor/pull/2505)).
### Fixes

19
Cargo.lock generated
View File

@ -67,9 +67,9 @@ dependencies = [
[[package]]
name = "aho-corasick"
version = "0.7.19"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e"
checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04"
dependencies = [
"memchr",
]
@ -179,6 +179,7 @@ dependencies = [
"heck 0.4.0",
"pathdiff",
"portpicker",
"regex",
"reqwest",
"semver 1.0.16",
"serde",
@ -2155,7 +2156,7 @@ dependencies = [
"petgraph",
"pico-args",
"regex",
"regex-syntax",
"regex-syntax 0.6.27",
"string_cache",
"term",
"tiny-keccak",
@ -3106,13 +3107,13 @@ dependencies = [
[[package]]
name = "regex"
version = "1.6.0"
version = "1.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
"regex-syntax 0.7.2",
]
[[package]]
@ -3121,6 +3122,12 @@ version = "0.6.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
[[package]]
name = "regex-syntax"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
[[package]]
name = "remove_dir_all"
version = "0.5.3"

View File

@ -40,6 +40,7 @@ dirs = "4.0"
heck = "0.4.0"
flate2 = "1.0.19"
tar = "0.4.35"
regex = "1.8.3"
reqwest = { version = "0.11.4", default-features = false, features = ["multipart", "blocking", "rustls-tls"] }
tokio = "1.24"
pathdiff = "0.2.0"

View File

@ -14,6 +14,7 @@ use flate2::read::ZlibDecoder;
use flate2::write::{GzEncoder, ZlibEncoder};
use flate2::Compression;
use heck::{ToKebabCase, ToSnakeCase};
use regex::RegexBuilder;
use reqwest::blocking::multipart::{Form, Part};
use reqwest::blocking::Client;
use semver::{Version, VersionReq};
@ -323,7 +324,14 @@ pub enum Command {
#[derive(Debug, Parser)]
pub enum KeysCommand {
/// List all of the program keys.
List,
/// Sync the program's `declare_id!` pubkey with the program's actual pubkey.
Sync {
/// Only sync the given program instead of all programs
#[clap(short, long)]
program_name: Option<String>,
},
}
#[derive(Debug, Parser)]
@ -3763,6 +3771,7 @@ fn registry_api_token(_cfg_override: &ConfigOverride) -> Result<String> {
fn keys(cfg_override: &ConfigOverride, cmd: KeysCommand) -> Result<()> {
match cmd {
KeysCommand::List => keys_list(cfg_override),
KeysCommand::Sync { program_name } => keys_sync(cfg_override, program_name),
}
}
@ -3776,6 +3785,81 @@ fn keys_list(cfg_override: &ConfigOverride) -> Result<()> {
})
}
/// Sync the program's `declare_id!` pubkey with the pubkey from `target/deploy/<KEYPAIR>.json`.
fn keys_sync(cfg_override: &ConfigOverride, program_name: Option<String>) -> Result<()> {
with_workspace(cfg_override, |cfg| {
let programs = cfg.read_all_programs()?;
let programs = match program_name {
Some(program_name) => vec![programs
.into_iter()
.find(|program| program.lib_name == program_name)
.ok_or_else(|| anyhow!("`{program_name}` is not found"))?],
None => programs,
};
let declare_id_regex = RegexBuilder::new(r#"^(([\w]+::)*)declare_id!\("(\w*)"\)"#)
.multi_line(true)
.build()
.unwrap();
for program in programs {
// Get the pubkey from the keypair file
let actual_program_id = program.pubkey()?.to_string();
// Handle declaration in program files
let src_path = program.path.join("src");
let files_to_check = vec![src_path.join("lib.rs"), src_path.join("id.rs")];
for path in files_to_check {
let mut content = match fs::read_to_string(&path) {
Ok(content) => content,
Err(_) => continue,
};
let incorrect_program_id = declare_id_regex
.captures(&content)
.and_then(|captures| captures.get(3))
.filter(|program_id_match| program_id_match.as_str() != actual_program_id);
if let Some(program_id_match) = incorrect_program_id {
println!("Found incorrect program id declaration in {path:?}");
// Update the program id
content.replace_range(program_id_match.range(), &actual_program_id);
fs::write(&path, content)?;
println!("Updated to {actual_program_id}\n");
break;
}
}
// Handle declaration in Anchor.toml
'outer: for programs in cfg.programs.values_mut() {
for (name, mut deployment) in programs {
// Skip other programs
if name != &program.lib_name {
continue;
}
if deployment.address.to_string() != actual_program_id {
println!("Found incorrect program id declaration in Anchor.toml for the program `{name}`");
// Update the program id
deployment.address = Pubkey::from_str(&actual_program_id).unwrap();
fs::write(cfg.path(), cfg.to_string())?;
println!("Updated to {actual_program_id}\n");
break 'outer;
}
}
}
}
println!("All program id declarations are synced.");
Ok(())
})
}
fn localnet(
cfg_override: &ConfigOverride,
skip_build: bool,