diff --git a/tools/compiler/Cargo.lock b/tools/compiler/Cargo.lock index 90c16b7..b193961 100644 --- a/tools/compiler/Cargo.lock +++ b/tools/compiler/Cargo.lock @@ -275,7 +275,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ "num-traits", - "rand", + "rand 0.8.5", ] [[package]] @@ -557,7 +557,7 @@ checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" dependencies = [ "byteorder", "digest 0.9.0", - "rand_core", + "rand_core 0.6.4", "subtle-ng", "zeroize", ] @@ -659,7 +659,7 @@ dependencies = [ "bitvec", "blake2b_simd 1.0.2", "decaf377 0.5.0", - "rand_core", + "rand_core 0.6.4", "thiserror", ] @@ -676,7 +676,7 @@ dependencies = [ "decaf377 0.5.0", "digest 0.9.0", "hex", - "rand_core", + "rand_core 0.6.4", "serde", "thiserror", ] @@ -778,7 +778,7 @@ checksum = "3c8465edc8ee7436ffea81d21a019b16676ee3db267aa8d5a8d729581ecf998b" dependencies = [ "curve25519-dalek-ng", "hex", - "rand_core", + "rand_core 0.6.4", "sha2 0.9.9", "zeroize", ] @@ -852,7 +852,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ "byteorder", - "rand", + "rand 0.8.5", "rustc-hex", "static_assertions", ] @@ -903,6 +903,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + [[package]] name = "funty" version = "2.0.0" @@ -1485,7 +1491,7 @@ checksum = "d1fcc7f316b2c079dde77564a1360639c1a956a23fa96122732e416cb10717bb" dependencies = [ "cfg-if", "num-traits", - "rand", + "rand 0.8.5", "static_assertions", ] @@ -1705,7 +1711,7 @@ checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" dependencies = [ "byteorder", "keccak", - "rand_core", + "rand_core 0.6.4", "zeroize", ] @@ -2062,8 +2068,8 @@ dependencies = [ "penumbra-num", "penumbra-proto", "poseidon377", - "rand", - "rand_core", + "rand 0.8.5", + "rand_core 0.6.4", "regex", "serde", "serde_with", @@ -2099,8 +2105,8 @@ dependencies = [ "num-bigint", "once_cell", "penumbra-proto", - "rand", - "rand_core", + "rand 0.8.5", + "rand_core 0.6.4", "regex", "serde", "sha2 0.10.8", @@ -2147,6 +2153,7 @@ dependencies = [ "reqwest", "serde", "serde_json", + "tempdir", "thiserror", "tokio", "tracing", @@ -2242,7 +2249,7 @@ dependencies = [ "num", "num-bigint", "poseidon-parameters", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -2412,6 +2419,19 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + [[package]] name = "rand" version = "0.8.5" @@ -2420,7 +2440,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -2430,9 +2450,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", ] +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + [[package]] name = "rand_core" version = "0.6.4" @@ -2442,6 +2477,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -2505,6 +2549,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + [[package]] name = "reqwest" version = "0.12.3" @@ -2977,6 +3030,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "tempdir" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" +dependencies = [ + "rand 0.4.6", + "remove_dir_all", +] + [[package]] name = "tempfile" version = "3.10.1" diff --git a/tools/compiler/Cargo.toml b/tools/compiler/Cargo.toml index 99b47c2..5e18fe4 100644 --- a/tools/compiler/Cargo.toml +++ b/tools/compiler/Cargo.toml @@ -13,7 +13,8 @@ serde = { version = "1.0.197", features = ["derive"] } serde_json = "1.0.115" regress = "0.9.1" reqwest = { version = "0.12.3", features = ["json"] } +tempdir = "0.3.7" thiserror = "1.0.58" tokio = { version = "1.37.0", features = ["full"] } -tracing-subscriber = "0.3" -tracing = "0.1" +tracing-subscriber = "0.3.18" +tracing = "0.1.40" diff --git a/tools/compiler/src/parser.rs b/tools/compiler/src/parser.rs index ae28d8d..f9db731 100644 --- a/tools/compiler/src/parser.rs +++ b/tools/compiler/src/parser.rs @@ -38,7 +38,7 @@ pub struct IbcConnection { } pub const LOCAL_REGISTRY_DIR: &str = "../../registry"; -const LOCAL_INPUT_DIR: &str = "../../input"; +pub const LOCAL_INPUT_DIR: &str = "../../input"; /// Retrieves a list of `ChainConfig` objects representing the configuration for various chains. /// This function assumes a specific directory structure and configs inside: @@ -46,15 +46,15 @@ const LOCAL_INPUT_DIR: &str = "../../input"; /// input/ /// ├── penumbra-testnet-deimos-6.json /// └── mars-1.json -pub fn get_chain_configs() -> AppResult> { +pub fn get_chain_configs(registry_dir: &str, input_dir: &str) -> AppResult> { // Clear registry output dir - let registry_dir = Path::new(LOCAL_REGISTRY_DIR); + let registry_dir = Path::new(registry_dir); if registry_dir.exists() { fs::remove_dir_all(registry_dir)?; } fs::create_dir_all(registry_dir)?; - let chain_configs = fs::read_dir(LOCAL_INPUT_DIR)?; + let chain_configs = fs::read_dir(input_dir)?; Ok(chain_configs .into_iter() .map(|input| -> AppResult { diff --git a/tools/compiler/src/processor.rs b/tools/compiler/src/processor.rs index 91bf84b..fe35a9a 100644 --- a/tools/compiler/src/processor.rs +++ b/tools/compiler/src/processor.rs @@ -10,7 +10,9 @@ use tokio::task; use crate::error::AppResult; use crate::github::assetlist_schema::AssetTypeAsset; -use crate::parser::{get_chain_configs, ChainConfig, IbcConnection, Rpc, LOCAL_REGISTRY_DIR}; +use crate::parser::{ + get_chain_configs, ChainConfig, IbcConnection, Rpc, LOCAL_INPUT_DIR, LOCAL_REGISTRY_DIR, +}; use crate::querier::query_github_assets; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -44,7 +46,7 @@ pub async fn generate_registry() -> AppResult<()> { let mut tasks = Vec::new(); // Get local configs from /input directory - let chain_configs = get_chain_configs()?; + let chain_configs = get_chain_configs(LOCAL_REGISTRY_DIR, LOCAL_INPUT_DIR)?; chain_configs.into_iter().for_each(|c| { // Async fetch metadata for ibc assets from cosmos registry let task = task::spawn(async move { process_chain_config(c).await }); @@ -65,7 +67,7 @@ pub async fn generate_registry() -> AppResult<()> { /// Given `ibc_data` describing a channel and `source_asset` on the source chain, /// compute the metadata for the asset when it is transported along the channel onto a Penumbra chain. -fn transport_metadata_along_channel( +pub fn transport_metadata_along_channel( ibc_data: &IbcConnection, source_asset: Metadata, ) -> AppResult { @@ -94,7 +96,7 @@ fn transport_metadata_along_channel( Ok(Metadata::try_from(pb_metadata)?) } -fn base64_id(m: &Metadata) -> AppResult { +pub fn base64_id(m: &Metadata) -> AppResult { let id_json = serde_json::to_value(m.id())?; let base64_str = id_json .get("inner") diff --git a/tools/compiler/tests/test_parser.rs b/tools/compiler/tests/test_parser.rs new file mode 100644 index 0000000..f49579c --- /dev/null +++ b/tools/compiler/tests/test_parser.rs @@ -0,0 +1,101 @@ +use penumbra_registry::parser::get_chain_configs; +use std::fs::File; +use std::io::Write; +use std::path::Path; +use tempdir::TempDir; + +fn create_test_config_file(dir: &Path, file_name: &str, contents: &str) { + let file_path = dir.join(file_name); + let mut file = File::create(file_path).unwrap(); + file.write_all(contents.as_bytes()).unwrap(); +} + +#[test] +fn test_get_chain_configs_reads_configs_correctly() { + let temp_input_dir = TempDir::new("test_input").unwrap(); + let temp_registry_dir = TempDir::new("test_registry").unwrap(); + + let config_content = serde_json::json!({ + "chainId": "test-chain-1", + "rpcs": [], + "ibcConnections": [], + "nativeAssets": [] + }) + .to_string(); + create_test_config_file(temp_input_dir.path(), "test-chain-1.json", &config_content); + + let configs = get_chain_configs( + temp_registry_dir.path().to_str().unwrap(), + temp_input_dir.path().to_str().unwrap(), + ) + .unwrap(); + assert_eq!(configs.len(), 1); + assert_eq!(configs[0].chain_id, "test-chain-1"); +} + +#[test] +fn test_get_chain_configs_reads_multiple_configs_correctly() { + let temp_input_dir = TempDir::new("test_input").unwrap(); + let temp_registry_dir = TempDir::new("test_registry").unwrap(); + + let config_content_1 = serde_json::json!({ + "chainId": "test-chain-1", + "rpcs": [], + "ibcConnections": [], + "nativeAssets": [] + }) + .to_string(); + create_test_config_file( + temp_input_dir.path(), + "test-chain-1.json", + &config_content_1, + ); + + let config_content_2 = serde_json::json!({ + "chainId": "test-chain-2", + "rpcs": [], + "ibcConnections": [], + "nativeAssets": [] + }) + .to_string(); + create_test_config_file( + temp_input_dir.path(), + "test-chain-2.json", + &config_content_2, + ); + + let configs = get_chain_configs( + temp_registry_dir.path().to_str().unwrap(), + temp_input_dir.path().to_str().unwrap(), + ) + .unwrap(); + + assert_eq!(configs.len(), 2); + assert!(configs + .iter() + .any(|config| config.chain_id == "test-chain-1")); + assert!(configs + .iter() + .any(|config| config.chain_id == "test-chain-2")); +} + +#[test] +fn test_get_chain_configs_handles_invalid_json() { + let temp_input_dir = TempDir::new("test_input").unwrap(); + let temp_registry_dir = TempDir::new("test_registry").unwrap(); + + let invalid_config_content = "{ invalid json }"; + create_test_config_file( + temp_input_dir.path(), + "invalid.json", + invalid_config_content, + ); + + let configs = get_chain_configs( + temp_registry_dir.path().to_str().unwrap(), + temp_input_dir.path().to_str().unwrap(), + ) + .unwrap(); + + assert_eq!(configs.len(), 0); +} diff --git a/tools/compiler/tests/test_processor.rs b/tools/compiler/tests/test_processor.rs new file mode 100644 index 0000000..fe5a058 --- /dev/null +++ b/tools/compiler/tests/test_processor.rs @@ -0,0 +1,74 @@ +use penumbra_registry::parser::IbcConnection; +use penumbra_registry::processor::{base64_id, transport_metadata_along_channel}; + +#[test] +fn base64_id_extracts_correctly() { + let asset_json = r#" + { + "base": "upenumbra", + "penumbraAssetId": { + "inner": "KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=" + } + }"#; + let metadata = serde_json::from_str(asset_json).unwrap(); + + assert_eq!( + base64_id(&metadata).unwrap(), + "KeqcLzNx9qSH5+lcJHBB9KNW+YPrBk5dKzvPMiypahA=" + ); +} + +#[test] +fn test_transport_metadata_along_channel() { + let ibc_data = IbcConnection { + ibc_channel: "channel-123".to_string(), + chain_id: "love-999".to_string(), + address_prefix: "love".to_string(), + cosmos_registry_dir: "love-124".to_string(), + }; + + let input_json = r#" + { + "denomUnits": [ + { + "denom": "gm", + "exponent": 6 + }, + { + "denom": "ugm" + } + ], + "base": "ugm", + "display": "gm", + "symbol": "GM", + "penumbraAssetId": { + "inner": "HW2Eq3UZVSBttoUwUi/MUtE7rr2UU7/UH500byp7OAc=" + } + } + "#; + let input_metadata = serde_json::from_str(input_json).unwrap(); + + let output_json = r#" + { + "denomUnits": [ + { + "denom": "transfer/channel-123/gm", + "exponent": 6 + }, + { + "denom": "transfer/channel-123/ugm" + } + ], + "base": "transfer/channel-123/ugm", + "display": "transfer/channel-123/gm", + "symbol": "GM", + "penumbraAssetId": { + "inner": "YGObCaxvA7dR5tg6FeoNDxIGbwl9HK5eYr7jFho/GwQ=" + } + } + "#; + let output_metadata = serde_json::from_str(output_json).unwrap(); + + let result = transport_metadata_along_channel(&ibc_data, input_metadata).unwrap(); + assert_eq!(result, output_metadata); +}