diff --git a/.gitignore b/.gitignore index 829a0be9..5751e6d4 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,5 @@ kinode/packages/**/wasi_snapshot_preview1.wasm kinode/packages/app_store/pkg/ui/* kinode/packages/homepage/pkg/ui/* -kinode/src/register-ui/build/* +kinode/src/register-ui/build/ +kinode/src/register-ui/dist/ diff --git a/Cargo.lock b/Cargo.lock index 44401cbb..ffacae25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -61,7 +61,7 @@ dependencies = [ "cfg-if", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -117,9 +117,9 @@ dependencies = [ [[package]] name = "alloy-chains" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1752d7d62e2665da650a36d84abbf239f812534475d51f072a49a533513b7cdd" +checksum = "47ff94ce0f141c2671c23d02c7b88990dd432856639595c5d010663d017c2c58" dependencies = [ "num_enum", "strum", @@ -199,7 +199,7 @@ dependencies = [ "itoa", "serde", "serde_json", - "winnow 0.6.15", + "winnow 0.6.16", ] [[package]] @@ -583,7 +583,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cbcba3ca07cf7975f15d871b721fb18031eec8bce51103907f6dcce00b255d98" dependencies = [ "serde", - "winnow 0.6.15", + "winnow 0.6.16", ] [[package]] @@ -692,9 +692,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", @@ -707,33 +707,33 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -1132,9 +1132,9 @@ dependencies = [ [[package]] name = "blst" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62dc83a094a71d43eeadd254b1ec2d24cb6a0bb6cadce00df51f0db594711a32" +checksum = "4378725facc195f1a538864863f6de233b500a8862747e7f165078a419d5e874" dependencies = [ "cc", "glob", @@ -1162,9 +1162,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" +checksum = "fca2be1d5c43812bae364ee3f30b3afcb7877cf59f4aeb94c66f313a41d2fac9" dependencies = [ "serde", ] @@ -1294,9 +1294,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" +checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" dependencies = [ "jobserver", "libc", @@ -1394,9 +1394,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.9" +version = "4.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462" +checksum = "35723e6a11662c2afb578bcf0b88bf6ea8e21282a953428f240574fcc3a2b5b3" dependencies = [ "clap_builder", "clap_derive", @@ -1404,9 +1404,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.9" +version = "4.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942" +checksum = "49eb96cbfa7cfa35017b7cd548c75b14c3118c98b423041d70562665e07fb0fa" dependencies = [ "anstream", "anstyle", @@ -1416,9 +1416,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.8" +version = "4.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" +checksum = "5d029b67f89d30bbb547c89fd5161293c0aec155fc691d7924b64550662db93e" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -1428,9 +1428,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "cloudabi" @@ -1479,9 +1479,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "const-hex" @@ -1731,7 +1731,7 @@ dependencies = [ "crossterm_winapi", "futures-core", "libc", - "mio", + "mio 0.8.11", "parking_lot", "signal-hook", "signal-hook-mio", @@ -3080,9 +3080,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -3139,9 +3139,9 @@ dependencies = [ [[package]] name = "jobserver" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] @@ -3313,7 +3313,7 @@ dependencies = [ [[package]] name = "kinode_process_lib" version = "0.9.0" -source = "git+https://github.com/kinode-dao/process_lib?branch=develop#9094586e6c816d1c44879f26ac6cced9e31dc839" +source = "git+https://github.com/kinode-dao/process_lib?branch=develop#05ab125d3e9e733f59301253c51bdf1b14f61140" dependencies = [ "alloy", "alloy-primitives", @@ -3554,9 +3554,9 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904" dependencies = [ "hashbrown 0.14.5", ] @@ -3691,6 +3691,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "mio" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +dependencies = [ + "hermit-abi", + "libc", + "wasi", + "windows-sys 0.52.0", +] + [[package]] name = "mucow" version = "0.1.0" @@ -3835,18 +3847,18 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -4185,9 +4197,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "dee4364d9f3b902ef14fab8a1ddffb783a1cb6b4bba3bfc1fa3922732c7de97f" +dependencies = [ + "zerocopy 0.6.6", +] [[package]] name = "primitive-types" @@ -4842,9 +4857,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.11" +version = "0.23.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4828ea528154ae444e5a642dbb7d5623354030dc9822b83fd9bb79683c7399d0" +checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" dependencies = [ "once_cell", "ring", @@ -5033,20 +5048,21 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.120" +version = "1.0.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" dependencies = [ "serde", ] @@ -5156,12 +5172,12 @@ dependencies = [ [[package]] name = "signal-hook-mio" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" +checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" dependencies = [ "libc", - "mio", + "mio 0.8.11", "signal-hook", ] @@ -5448,9 +5464,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.12.15" +version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4873307b7c257eddcb50c9bedf158eb669578359fb28428bef438fec8e6ba7c2" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" @@ -5588,27 +5604,26 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.38.1" +version = "1.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb2caba9f80616f438e09748d5acda951967e1ea58508ef53d9c6402485a46df" +checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" dependencies = [ "backtrace", "bytes", "libc", - "mio", - "num_cpus", + "mio 1.0.1", "pin-project-lite", "signal-hook-registry", "socket2 0.5.7", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", @@ -5693,21 +5708,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.15" +version = "0.8.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac2caab0bf757388c6c0ae23b3293fdb463fee59434529014f85e3263b995c28" +checksum = "7a44eede9b727419af8095cb2d72fab15487a541f54647ad4414b34096ee4631" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.16", + "toml_edit 0.22.18", ] [[package]] name = "toml_datetime" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] @@ -5725,15 +5740,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.16" +version = "0.22.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788" +checksum = "1490595c74d930da779e944f5ba2ecdf538af67df1a9848cbd156af43c1b7cf0" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.15", + "winnow 0.6.16", ] [[package]] @@ -6136,9 +6151,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wait-timeout" @@ -6995,9 +7010,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.15" +version = "0.6.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "557404e450152cd6795bb558bca69e43c585055f4606e3bcae5894fc6dac9ba0" +checksum = "b480ae9340fc261e6be3e95a1ba86d54ae3f9171132a73ce8d4bbaf68339507c" dependencies = [ "memchr", ] @@ -7184,13 +7199,34 @@ dependencies = [ "tap", ] +[[package]] +name = "zerocopy" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854e949ac82d619ee9a14c66a1b674ac730422372ccb759ce0c39cabcf2bf8e6" +dependencies = [ + "byteorder", + "zerocopy-derive 0.6.6", +] + [[package]] name = "zerocopy" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy-derive" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "125139de3f6b9d625c39e2efdd73d41bdac468ccd556556440e322be0e1bbd91" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", ] [[package]] diff --git a/kinode/packages/app_store/app_store/src/state.rs b/kinode/packages/app_store/app_store/src/state.rs index 23388e6f..b25dcedc 100644 --- a/kinode/packages/app_store/app_store/src/state.rs +++ b/kinode/packages/app_store/app_store/src/state.rs @@ -3,7 +3,7 @@ use crate::{KIMAP_ADDRESS, VFS_TIMEOUT}; use alloy_sol_types::SolEvent; use kinode_process_lib::kernel_types::Erc721Metadata; use kinode_process_lib::{ - eth, kernel_types as kt, kimap, net, println, vfs, Address, NodeId, PackageId, Request, + eth, kernel_types as kt, kimap, println, vfs, Address, NodeId, PackageId, Request, }; use serde::{Deserialize, Serialize}; use std::collections::{HashMap, HashSet}; @@ -371,31 +371,29 @@ impl State { ) -> Result<(), AppStoreLogError> { let block_number: u64 = log.block_number.ok_or(AppStoreLogError::NoBlockNumber)?; - let kimap::contract::Note::SIGNATURE_HASH = log.topics()[0] else { - return Ok(()); - }; + let note: kimap::Note = + kimap::decode_note_log(&log).ok_or(AppStoreLogError::DecodeLogError)?; - let note = kimap::contract::Note::decode_log_data(log.data(), false) - .map_err(|_| AppStoreLogError::DecodeLogError)?; - - // use kns_indexer to convert nodehash to a kimap name - let package_full_path = - net::get_name(¬e.nodehash.to_string(), log.block_number, Some(10)) - .ok_or(AppStoreLogError::GetNameError)?; + let package_id = note + .parent_path + .split_once('.') + .ok_or(AppStoreLogError::InvalidPublisherName) + .and_then(|(package, publisher)| { + if package.is_empty() || publisher.is_empty() { + Err(AppStoreLogError::InvalidPublisherName) + } else { + Ok(PackageId::new(&package, &publisher)) + } + })?; // the app store exclusively looks for ~metadata-uri postings: if one is // observed, we then *query* for ~metadata-hash to verify the content // at the URI. // - // this means that ~metadata-hash should be *posted before or at the same time* as ~metadata-uri! - let Ok("~metadata-uri") = std::str::from_utf8(¬e.note) else { - return Ok(()); - }; - let metadata_uri = String::from_utf8_lossy(¬e.data).to_string(); // generate ~metadata-hash notehash - let hash_note = format!("~metadata-hash.{package_full_path}"); + let hash_note = format!("~metadata-hash.{}", note.parent_path); // owner can change which we don't track (yet?) so don't save, need to get when desired let (tba, _owner, data) = self.kimap.get(&hash_note).map_err(|e| { @@ -403,51 +401,48 @@ impl State { AppStoreLogError::MetadataHashMismatch })?; - if let Some(hash_note) = data { - let metadata_hash = String::from_utf8_lossy(&hash_note).to_string(); + let Some(hash_note) = data else { + return Err(AppStoreLogError::MetadataNotFound); + }; - // fetch metadata from the URI (currently only handling HTTP(S) URLs!) - // assert that the metadata hash matches the fetched data - let metadata = utils::fetch_metadata_from_url(&metadata_uri, &metadata_hash, 30)?; + let metadata_hash = String::from_utf8_lossy(&hash_note).to_string(); - let (package_name, publisher_name) = package_full_path - .split_once('.') - .ok_or(AppStoreLogError::InvalidPublisherName) - .and_then(|(package, publisher)| { - if package.is_empty() || publisher.is_empty() { - Err(AppStoreLogError::InvalidPublisherName) - } else { - Ok((package, publisher)) - } - })?; + // fetch metadata from the URI (currently only handling HTTP(S) URLs!) + // assert that the metadata hash matches the fetched data + let metadata = if update_listings { + Some(utils::fetch_metadata_from_url( + &metadata_uri, + &metadata_hash, + 30, + )?) + } else { + None + }; - let package_id = PackageId::new(&package_name, &publisher_name); - - println!("got new app with valid metadata: {package_id}"); - - match self.packages.entry(package_id) { - std::collections::hash_map::Entry::Occupied(mut listing) => { - let listing = listing.get_mut(); - listing.tba = tba; - listing.metadata_uri = metadata_uri; - listing.metadata_hash = metadata_hash; - listing.metadata = Some(metadata); + match self.packages.entry(package_id) { + std::collections::hash_map::Entry::Occupied(mut listing) => { + let listing = listing.get_mut(); + listing.tba = tba; + listing.metadata_uri = metadata_uri; + listing.metadata_hash = metadata_hash; + if update_listings { + listing.metadata = metadata; } - std::collections::hash_map::Entry::Vacant(listing) => { - listing.insert(PackageListing { - tba, - metadata_uri, - metadata_hash, - metadata: Some(metadata), - state: None, - }); - } - }; - } + } + std::collections::hash_map::Entry::Vacant(listing) => { + listing.insert(PackageListing { + tba, + metadata_uri, + metadata_hash, + metadata, + state: None, + }); + } + }; self.last_saved_block = block_number; - if update_listings { - // kinode_process_lib::set_state(&serde_json::to_vec(self).unwrap()); - } + // if update_listings { + // kinode_process_lib::set_state(&serde_json::to_vec(self).unwrap()); + // } Ok(()) } @@ -456,17 +451,13 @@ impl State { /// of stale metadata. pub fn update_listings(&mut self) { for (package_id, listing) in self.packages.iter_mut() { - if listing.metadata.is_none() { - if let Ok(metadata) = utils::fetch_metadata_from_url( - &listing.metadata_uri, - &listing.metadata_hash, - 30, - ) { - if let Some(package_state) = &listing.state { - auto_update(&self.our, package_id, &metadata, package_state); - } - listing.metadata = Some(metadata); + if let Ok(metadata) = + utils::fetch_metadata_from_url(&listing.metadata_uri, &listing.metadata_hash, 30) + { + if let Some(package_state) = &listing.state { + auto_update(&self.our, package_id, &metadata, package_state); } + listing.metadata = Some(metadata); } } // kinode_process_lib::set_state(&serde_json::to_vec(self).unwrap()); diff --git a/kinode/packages/kns_indexer/kns_indexer/src/lib.rs b/kinode/packages/kns_indexer/kns_indexer/src/lib.rs index d834aff9..1efd37b6 100644 --- a/kinode/packages/kns_indexer/kns_indexer/src/lib.rs +++ b/kinode/packages/kns_indexer/kns_indexer/src/lib.rs @@ -4,7 +4,7 @@ use crate::kinode::process::kns_indexer::{ use alloy_sol_types::SolEvent; use kinode_process_lib::{ await_message, call_init, eth, kimap, net, print_to_terminal, println, Address, Message, - ProcessId, Request, Response, + Request, Response, }; use serde::{Deserialize, Serialize}; use std::{ @@ -123,7 +123,7 @@ fn main(our: Address, mut state: State) -> anyhow::Result<()> { println!("subscribing to new logs..."); subscribe_to_logs(ð_provider, mints_filter.clone(), 1); subscribe_to_logs(ð_provider, notes_filter.clone(), 2); - listen_to_new_blocks(&our); // sub_id: 3 + listen_to_new_blocks(); // sub_id: 3 println!("subscribed to logs successfully"); let mut pending_requests: BTreeMap> = BTreeMap::new(); @@ -231,7 +231,7 @@ fn handle_eth_message( } else if e.id == 2 { subscribe_to_logs(ð_provider, notes_filter.clone(), 2); } else if e.id == 3 { - listen_to_new_blocks(&our); + listen_to_new_blocks(); } } Err(e) => { @@ -301,32 +301,36 @@ fn handle_log(our: &Address, state: &mut State, log: ð::Log) -> anyhow::Resul let decoded = kimap::contract::Mint::decode_log_data(log.data(), true).unwrap(); let parent_hash = decoded.parenthash.to_string(); let child_hash = decoded.childhash.to_string(); - let label = String::from_utf8(decoded.name.to_vec())?; + let name = String::from_utf8(decoded.name.to_vec())?; - let name = match get_parent_name(&state.names, &parent_hash) { - Some(parent_name) => format!("{}.{}", label, parent_name), - None => label, + if !kimap::valid_name(&name, false) { + return Err(anyhow::anyhow!("skipping invalid entry")); + } + + let full_name = match get_parent_name(&state.names, &parent_hash) { + Some(parent_name) => format!("{name}.{parent_name}"), + None => name, }; - state.names.insert(child_hash.clone(), name.clone()); + state.names.insert(child_hash.clone(), full_name.clone()); state.nodes.insert( - name.clone(), + full_name.clone(), net::KnsUpdate { - name: name.clone(), + name: full_name.clone(), public_key: String::new(), ips: Vec::new(), ports: BTreeMap::new(), routers: Vec::new(), }, ); - name + full_name } kimap::contract::Note::SIGNATURE_HASH => { let decoded = kimap::contract::Note::decode_log_data(log.data(), true).unwrap(); let note = String::from_utf8(decoded.note.to_vec())?; - let node_hash = decoded.nodehash.to_string(); + let node_hash = decoded.parenthash.to_string(); let Some(node_name) = get_parent_name(&state.names, &node_hash) else { return Err(anyhow::anyhow!("parent node for note not found")); @@ -510,19 +514,18 @@ pub fn bytes_to_port(bytes: &[u8]) -> anyhow::Result { } } -fn listen_to_new_blocks(our: &Address) { +fn listen_to_new_blocks() { let eth_newheads_sub = eth::EthAction::SubscribeLogs { sub_id: 3, chain_id: CHAIN_ID, kind: eth::SubscriptionKind::NewHeads, params: eth::Params::Bool(false), }; - let our_eth = Address::new(our.node(), ProcessId::new(Some("eth"), "distro", "sys")); - Request::new() + Request::to(("our", "eth", "distro", "sys")) .body(serde_json::to_vec(ð_newheads_sub).unwrap()) - .target(our_eth) - .send(); + .send() + .unwrap(); } fn subscribe_to_logs(eth_provider: ð::Provider, filter: eth::Filter, sub_id: u64) { diff --git a/kinode/src/eth/mod.rs b/kinode/src/eth/mod.rs index 2ca7d26d..cba7e8c1 100644 --- a/kinode/src/eth/mod.rs +++ b/kinode/src/eth/mod.rs @@ -159,6 +159,38 @@ struct ModuleState { print_tx: PrintSender, } +/// TODO replace with alloy abstraction +fn valid_method(method: &str) -> Option<&'static str> { + match method { + "eth_getBalance" => Some("eth_getBalance"), + "eth_sendRawTransaction" => Some("eth_sendRawTransaction"), + "eth_call" => Some("eth_call"), + "eth_chainId" => Some("eth_chainId"), + "eth_getTransactionReceipt" => Some("eth_getTransactionReceipt"), + "eth_getTransactionCount" => Some("eth_getTransactionCount"), + "eth_estimateGas" => Some("eth_estimateGas"), + "eth_blockNumber" => Some("eth_blockNumber"), + "eth_getBlockByHash" => Some("eth_getBlockByHash"), + "eth_getBlockByNumber" => Some("eth_getBlockByNumber"), + "eth_getTransactionByHash" => Some("eth_getTransactionByHash"), + "eth_getCode" => Some("eth_getCode"), + "eth_getStorageAt" => Some("eth_getStorageAt"), + "eth_gasPrice" => Some("eth_gasPrice"), + "eth_accounts" => Some("eth_accounts"), + "eth_hashrate" => Some("eth_hashrate"), + "eth_getLogs" => Some("eth_getLogs"), + "eth_subscribe" => Some("eth_subscribe"), + "eth_unsubscribe" => Some("eth_unsubscribe"), + // "eth_mining" => Some("eth_mining"), + // "net_version" => Some("net_version"), + // "net_peerCount" => Some("net_peerCount"), + // "net_listening" => Some("net_listening"), + // "web3_clientVersion" => Some("web3_clientVersion"), + // "web3_sha3" => Some("web3_sha3"), + _ => None, + } +} + /// The ETH provider runtime process is responsible for connecting to one or more ETH RPC providers /// and using them to service indexing requests from other apps. This is the runtime entry point /// for the entire module. @@ -578,7 +610,7 @@ async fn fulfill_request( else { return EthResponse::Err(EthError::PermissionDenied); // will never hit }; - let Some(method) = to_static_str(&method) else { + let Some(method) = valid_method(&method) else { return EthResponse::Err(EthError::InvalidMethod(method.to_string())); }; let Some(mut aps) = providers.get_mut(&chain_id) else { diff --git a/kinode/src/register-ui/src/components/EnterKnsName.tsx b/kinode/src/register-ui/src/components/EnterKnsName.tsx index b21e7784..a12f0795 100644 --- a/kinode/src/register-ui/src/components/EnterKnsName.tsx +++ b/kinode/src/register-ui/src/components/EnterKnsName.tsx @@ -6,6 +6,13 @@ import { usePublicClient } from 'wagmi' import { KINOMAP, kinomapAbi } from '../abis' import { kinohash } from "../utils/kinohash"; +export const NAME_URL = "Name must contain only valid characters (a-z, 0-9, and -)"; +export const NAME_LENGTH = "Name must be 9 characters or more"; +export const NAME_CLAIMED = "Name is already claimed"; +export const NAME_INVALID_PUNY = "Unsupported punycode character"; +export const NAME_NOT_OWNER = "Name already exists and does not belong to this wallet"; +export const NAME_NOT_REGISTERED = "Name is not registered"; + type ClaimOsNameProps = { name: string; setName: React.Dispatch>; @@ -23,12 +30,6 @@ function EnterKnsName({ triggerNameCheck, isReset = false, }: ClaimOsNameProps) { - const NAME_URL = - "Name must be a valid URL without subdomains (A-Z, a-z, 0-9, and punycode)"; - const NAME_LENGTH = "Name must be 9 characters or more"; - const NAME_CLAIMED = "Name is already claimed"; - const NAME_INVALID_PUNY = "Unsupported punycode character"; - const client = usePublicClient(); const debouncer = useRef(null); @@ -68,7 +69,7 @@ function EnterKnsName({ if (validities.length === 0 || index !== -1 && normalized.length > 2) { try { const namehash = kinohash(normalized) - // maybe separate into helper function for readability? + // maybe separate into helper function for readability? // also note picking the right chain ID & address! const data = await client?.readContract({ address: KINOMAP, diff --git a/kinode/src/register-ui/src/pages/ResetKnsName.tsx b/kinode/src/register-ui/src/pages/ResetKnsName.tsx index a95ab79d..3ca08ecb 100644 --- a/kinode/src/register-ui/src/pages/ResetKnsName.tsx +++ b/kinode/src/register-ui/src/pages/ResetKnsName.tsx @@ -19,12 +19,7 @@ import { useAccount, usePublicClient, useWaitForTransactionReceipt, useWriteCont import { useConnectModal, useAddRecentTransaction } from "@rainbow-me/rainbowkit"; import { kinohash } from "../utils/kinohash"; -const NAME_INVALID_PUNY = "Unsupported punycode character"; -const NAME_NOT_OWNER = "Name does not belong to this wallet"; -const NAME_NOT_REGISTERED = "Name is not registered"; -const NAME_URL = - "Name must be a valid URL without subdomains (A-Z, a-z, 0-9, and punycode)"; - +import { NAME_URL, NAME_INVALID_PUNY, NAME_NOT_OWNER, NAME_NOT_REGISTERED } from "../components/EnterKnsName"; interface ResetProps extends PageProps { } @@ -109,7 +104,7 @@ function ResetKnsName({ const namehash = kinohash(normalized) console.log('normalized', normalized) console.log('namehash', namehash) - // maybe separate into helper function for readability? + // maybe separate into helper function for readability? // also note picking the right chain ID & address! const data = await client?.readContract({ address: KINOMAP, diff --git a/lib/src/core.rs b/lib/src/core.rs index 8d1660e5..f294a2b1 100644 --- a/lib/src/core.rs +++ b/lib/src/core.rs @@ -20,12 +20,13 @@ lazy_static::lazy_static! { } // -// types shared between kernel and processes. frustratingly, this is an exact copy -// of the types in process_lib -// this is because even though the types are identical, they will not match when -// used in the kernel context which generates bindings differently than the process -// standard library. make sure to keep this synced with process_lib. +// Types shared between kernel and processes generated by `kinode.wit`. +// This is a copy of the types in `process_lib`. Even though the types +// are identical, they will not match when used in the kernel context +// which generates bindings differently than the process standard library. +// Make sure to keep this synced with process_lib. // + pub type Context = Vec; pub type NodeId = String; // KNS domain name @@ -60,68 +61,6 @@ impl<'a> Deserialize<'a> for ProcessId { } } -/// PackageId is like a ProcessId, but for a package. Only contains the name -/// of the package and the name of the publisher. -#[derive(Hash, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)] -pub struct PackageId { - package_name: String, - publisher_node: String, -} - -impl PackageId { - pub fn new(package_name: &str, publisher_node: &str) -> Self { - PackageId { - package_name: package_name.into(), - publisher_node: publisher_node.into(), - } - } - pub fn _package(&self) -> &str { - &self.package_name - } - pub fn _publisher(&self) -> &str { - &self.publisher_node - } -} - -impl std::str::FromStr for PackageId { - type Err = ProcessIdParseError; - /// Attempt to parse a `PackageId` from a string. The string must - /// contain exactly two segments, where segments are non-empty strings - /// separated by a colon (`:`). The segments cannot themselves contain colons. - /// - /// Please note that while any string without colons will parse successfully - /// to create a `PackageId`, not all strings without colons are actually - /// valid usernames, which the `publisher_node` field of a `PackageId` will - /// always in practice be. - fn from_str(input: &str) -> Result { - let segments: Vec<&str> = input.split(':').collect(); - if segments.len() < 2 { - return Err(ProcessIdParseError::MissingField); - } else if segments.len() > 2 { - return Err(ProcessIdParseError::TooManyColons); - } - let package_name = segments[0].to_string(); - if package_name.is_empty() { - return Err(ProcessIdParseError::MissingField); - } - let publisher_node = segments[1].to_string(); - if publisher_node.is_empty() { - return Err(ProcessIdParseError::MissingField); - } - - Ok(PackageId { - package_name, - publisher_node, - }) - } -} - -impl std::fmt::Display for PackageId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}:{}", self.package_name, self.publisher_node) - } -} - /// ProcessId is defined in the wit bindings, but constructors and methods /// are defined here. impl ProcessId { @@ -225,14 +164,6 @@ impl std::fmt::Display for ProcessId { } } -// impl PartialEq for ProcessId { -// fn eq(&self, other: &Self) -> bool { -// self.process_name == other.process_name -// && self.package_name == other.package_name -// && self.publisher_node == other.publisher_node -// } -// } - impl PartialEq<&str> for ProcessId { fn eq(&self, other: &&str) -> bool { &self.to_string() == other @@ -245,6 +176,70 @@ impl PartialEq for &str { } } +/// PackageId is like a ProcessId, but for a package. Only contains the name +/// of the package and the name of the publisher. +#[derive(Hash, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)] +pub struct PackageId { + package_name: String, + publisher_node: String, +} + +impl PackageId { + pub fn new(package_name: &str, publisher_node: &str) -> Self { + PackageId { + package_name: package_name.into(), + publisher_node: publisher_node.into(), + } + } + pub fn _package(&self) -> &str { + &self.package_name + } + pub fn _publisher(&self) -> &str { + &self.publisher_node + } +} + +impl std::str::FromStr for PackageId { + type Err = ProcessIdParseError; + /// Attempt to parse a `PackageId` from a string. The string must + /// contain exactly two segments, where segments are non-empty strings + /// separated by a colon (`:`). The segments cannot themselves contain colons. + /// + /// Please note that while any string without colons will parse successfully + /// to create a `PackageId`, not all strings without colons are actually + /// valid usernames, which the `publisher_node` field of a `PackageId` will + /// always in practice be. + fn from_str(input: &str) -> Result { + let segments: Vec<&str> = input.split(':').collect(); + if segments.len() < 2 { + return Err(ProcessIdParseError::MissingField); + } else if segments.len() > 2 { + return Err(ProcessIdParseError::TooManyColons); + } + let package_name = segments[0].to_string(); + if package_name.is_empty() { + return Err(ProcessIdParseError::MissingField); + } + let publisher_node = segments[1].to_string(); + if publisher_node.is_empty() { + return Err(ProcessIdParseError::MissingField); + } + + Ok(PackageId { + package_name, + publisher_node, + }) + } +} + +impl std::fmt::Display for PackageId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}:{}", self.package_name, self.publisher_node) + } +} + +/// Errors that can occur when parsing a [`ProcessId`] from a string. +/// Also used for [`PackageId`]. #[derive(Debug)] pub enum ProcessIdParseError { TooManyColons, @@ -273,6 +268,8 @@ impl std::error::Error for ProcessIdParseError { } } +/// An address is a node ID and a process ID, to uniquely globally identify a process. +/// The [`NodeId`] is the KNS name of the node that the process is running on. #[derive(Clone, Debug, Hash, Eq, PartialEq)] pub struct Address { pub node: NodeId, @@ -985,7 +982,7 @@ pub fn en_wit_send_error_kind_v0(kind: SendErrorKind) -> crate::v0::wit::SendErr } // -// END SYNC WITH process_lib +// END SYNC with process_lib // // @@ -1304,9 +1301,9 @@ impl Printout { } } -// kernel sets in case, e.g., -// A requests response from B does not request response from C -// -> kernel sets `Some(A) = Rsvp` for B's request to C +/// kernel sets in case, e.g., +/// A requests response from B does not request response from C +/// -> kernel sets `Some(A) = Rsvp` for B's request to C pub type Rsvp = Option
; #[derive(Debug, Serialize, Deserialize)] @@ -1555,6 +1552,7 @@ pub struct PackageManifestEntry { pub public: bool, } +/// IPC Requests for the state:distro:sys runtime module. #[derive(Serialize, Deserialize, Debug)] pub enum StateAction { GetState(ProcessId), @@ -1563,6 +1561,7 @@ pub enum StateAction { Backup, } +/// Responses for the state:distro:sys runtime module. #[derive(Serialize, Deserialize, Debug)] pub enum StateResponse { GetState, @@ -1590,7 +1589,6 @@ pub enum StateError { IOError { error: String }, } -#[allow(dead_code)] impl StateError { pub fn kind(&self) -> &str { match *self { @@ -1605,6 +1603,7 @@ impl StateError { } } +/// IPC Request format for the vfs:distro:sys runtime module. #[derive(Debug, Serialize, Deserialize)] pub struct VfsRequest { pub path: String, @@ -1703,7 +1702,6 @@ pub enum VfsError { CreateDirError { path: String, error: String }, } -#[allow(dead_code)] impl VfsError { pub fn kind(&self) -> &str { match *self { @@ -1720,6 +1718,7 @@ impl VfsError { } } +/// IPC Request format for the kv:distro:sys runtime module. #[derive(Debug, Serialize, Deserialize)] pub struct KvRequest { pub package_id: PackageId, @@ -1765,6 +1764,7 @@ pub enum KvError { IOError { error: String }, } +/// IPC Request format for the sqlite:distro:sys runtime module. #[derive(Debug, Serialize, Deserialize)] pub struct SqliteRequest { pub package_id: PackageId, @@ -1832,12 +1832,6 @@ pub enum SqliteError { InputError { error: String }, } -#[derive(Debug, Serialize, Deserialize)] -pub enum MessageType { - Request, - Response, -} - impl std::fmt::Display for KvAction { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{:?}", self) @@ -1975,6 +1969,7 @@ impl From> for SqliteError { } } +/// IPC Request format for the timer:distro:sys runtime module. #[derive(Debug, Clone, Serialize, Deserialize)] pub enum TimerAction { Debug, @@ -1985,10 +1980,6 @@ pub enum TimerAction { // networking protocol types // -// TODO: granular caps. -// "root": ConnectionRequest, KnsUpdate, KnsBatchUpdate, AddName, Sign? -// note: AddName is for no KnsEntry but still want to add a namehash - /// Must be parsed from message pack vector. /// all Get actions must be sent from local process. used for debugging #[derive(Clone, Debug, Serialize, Deserialize)] @@ -1997,9 +1988,9 @@ pub enum NetAction { /// We should respond (if we desire) by using them to initialize a routed connection /// with the NodeId given. ConnectionRequest(NodeId), - /// can only receive from trusted source, for now just ourselves locally, - /// in the future could get from remote provider + /// can only receive from trusted source: requires net root cap KnsUpdate(KnsUpdate), + /// can only receive from trusted source: requires net root cap KnsBatchUpdate(Vec), /// get a list of peers we are connected to GetPeers, @@ -2015,17 +2006,15 @@ pub enum NetAction { /// the given source. if the signer is not in our representation of /// the PKI, will not verify. /// **the `from` [`Address`] will always be prepended to the payload** - Verify { - from: Address, - signature: Vec, - }, + Verify { from: Address, signature: Vec }, } -/// For now, only sent in response to a ConnectionRequest. /// Must be parsed from message pack vector #[derive(Clone, Debug, Serialize, Deserialize)] pub enum NetResponse { + /// response to [`NetAction::ConnectionRequest`] Accepted(NodeId), + /// response to [`NetAction::ConnectionRequest`] Rejected(NodeId), /// response to [`NetAction::GetPeers`] Peers(Vec), @@ -2060,21 +2049,3 @@ impl KnsUpdate { self.ports.get(protocol) } } - -#[derive(Debug, Serialize, Deserialize)] -pub enum IndexerRequests { - NamehashToName(NamehashToNameRequest), - // other KNS requests are not used in process_lib, can be found in the kns api. -} - -#[derive(Clone, Debug, Serialize, Deserialize, Hash, Eq, PartialEq)] -pub struct NamehashToNameRequest { - pub hash: String, - pub block: Option, -} - -#[derive(Debug, Serialize, Deserialize)] -pub enum IndexerResponses { - Name(Option), - // other KNS responses are not used in process_lib, can be found in the kns api. -} diff --git a/lib/src/eth.rs b/lib/src/eth.rs index 26922e6b..db4f05dd 100644 --- a/lib/src/eth.rs +++ b/lib/src/eth.rs @@ -168,40 +168,3 @@ impl std::cmp::PartialEq for NodeOrRpcUrl { } } } - -// -// Internal types -// - -/// For static lifetimes of method strings. -/// Replaced soon by alloy-rs network abstraction. -pub fn to_static_str(method: &str) -> Option<&'static str> { - match method { - "eth_getBalance" => Some("eth_getBalance"), - "eth_sendRawTransaction" => Some("eth_sendRawTransaction"), - "eth_call" => Some("eth_call"), - "eth_chainId" => Some("eth_chainId"), - "eth_getTransactionReceipt" => Some("eth_getTransactionReceipt"), - "eth_getTransactionCount" => Some("eth_getTransactionCount"), - "eth_estimateGas" => Some("eth_estimateGas"), - "eth_blockNumber" => Some("eth_blockNumber"), - "eth_getBlockByHash" => Some("eth_getBlockByHash"), - "eth_getBlockByNumber" => Some("eth_getBlockByNumber"), - "eth_getTransactionByHash" => Some("eth_getTransactionByHash"), - "eth_getCode" => Some("eth_getCode"), - "eth_getStorageAt" => Some("eth_getStorageAt"), - "eth_gasPrice" => Some("eth_gasPrice"), - "eth_accounts" => Some("eth_accounts"), - "eth_hashrate" => Some("eth_hashrate"), - "eth_getLogs" => Some("eth_getLogs"), - "eth_subscribe" => Some("eth_subscribe"), - "eth_unsubscribe" => Some("eth_unsubscribe"), - // "eth_mining" => Some("eth_mining"), - // "net_version" => Some("net_version"), - // "net_peerCount" => Some("net_peerCount"), - // "net_listening" => Some("net_listening"), - // "web3_clientVersion" => Some("web3_clientVersion"), - // "web3_sha3" => Some("web3_sha3"), - _ => None, - } -} diff --git a/lib/src/http/server_types.rs b/lib/src/http/server_types.rs index 7d363c05..224850fe 100644 --- a/lib/src/http/server_types.rs +++ b/lib/src/http/server_types.rs @@ -1,4 +1,4 @@ -use crate::core::{LazyLoadBlob, MessageType}; +use crate::core::LazyLoadBlob; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use thiserror::Error; @@ -144,6 +144,13 @@ pub enum HttpServerAction { WebSocketClose(u32), } +/// Whether the WebSocketPush is a request or a response. +#[derive(Debug, Serialize, Deserialize)] +pub enum MessageType { + Request, + Response, +} + /// The possible message types for WebSocketPush. Ping and Pong are limited to 125 bytes /// by the WebSockets protocol. Text will be sent as a Text frame, with the lazy_load_blob bytes /// being the UTF-8 encoding of the string. Binary will be sent as a Binary frame containing