diff --git a/Cargo.lock b/Cargo.lock index 8dc6989d3..362acc072 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4562,6 +4562,7 @@ name = "metadata-cli" version = "0.1.0" dependencies = [ "anyhow", + "axon-protocol", "axon-types", "clap 4.4.6", "hex", diff --git a/devtools/metadata-cli/Cargo.toml b/devtools/metadata-cli/Cargo.toml index b04a5a0b0..096f18fe8 100644 --- a/devtools/metadata-cli/Cargo.toml +++ b/devtools/metadata-cli/Cargo.toml @@ -10,6 +10,7 @@ path = "src/main.rs" [dependencies] anyhow = "1.0.75" +axon-protocol = { path = "../../protocol" } axon-types = { git = "https://github.com/axonweb3/axon-contract.git", rev = "b82a843" } clap = { version = "4.4.6", features = ["derive"] } hex = "0.4.3" diff --git a/devtools/metadata-cli/README.md b/devtools/metadata-cli/README.md index 9a07a6e56..485185118 100644 --- a/devtools/metadata-cli/README.md +++ b/devtools/metadata-cli/README.md @@ -23,3 +23,23 @@ From JSONRPC metadata result: ```command $ curl 'https://rpc-alphanet-axon.ckbapp.dev/' --header 'Content-Type: application/json' -d '{"jsonrpc":"2.0","method":"axon_getCurrentMetadata","id":3}' | jq '.result' | axon-metadata get-data -i /dev/stdin ``` + +### Deploy the Metadata Cell + +After generating the cell data, you can deploy a metadata type-id cell with e.g. `ckb-cli wallet transfer` or `ckb-cli deploy`. + +## Parse Data + +Parse `MetadataCellData` to get validators. + +Usage: + +```command +$ axon-metadata parse-data -i data.example.hex +``` + +From JSONRPC cell data: + +```command +$ curl 'https://testnet.ckbapp.dev/' --header 'Content-Type: application/json' -d '{"jsonrpc":"2.0","method":"get_live_cell","params":[{"index":"0x0","tx_hash":"0x8a37967294c40da9ede155156bfe87d4b4e644c2b7f3275dd2ec4ebe4d695e24"},true],"id":3}' | jq -r '.result.cell.data.content' | axon-metadata parse-data -i /dev/stdin +``` diff --git a/devtools/metadata-cli/data.example.hex b/devtools/metadata-cli/data.example.hex new file mode 100644 index 000000000..049d38b1c --- /dev/null +++ b/devtools/metadata-cli/data.example.hex @@ -0,0 +1 @@ +0xad05000028000000290000003100000041000000490000004a0000004b0000006b000000d30200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000068020000480000006800000088000000a8000000c8000000e80000000801000028010000480100006801000088010000a8010000c8010000e801000008020000280200004802000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000da02000008000000d20200003c0000004000000044000000460000004e000000560000005a000000b2020000b6020000ba020000be020000c2020000c6020000ca0200000000000000000000000000000000000000000000000000000000000000005802000014000000a500000036010000c7010000910000001c0000004c0000006d000000810000008500000089000000a26e3fe1cf51bd4822072c61bdc315ac32e3d3c2e2484bb92942666399e863b4bf56cf2926383cc706ffc15dfebc85c6031ddc35212b7fc7ff6685b17d91f77c972535aee5c7ae5684d3e72b986f08834b8ab0cf264df99d83525e9e11c7e4db01558ae1b101000000010000000000000000000000910000001c0000004c0000006d00000081000000850000008900000080310fa9df724b5603d283b472ed3bf85254a8a4ceda8a274b421f6cf2be1d9184267cdfe9a199d36ff14e57668a55d002b77c74eb68af3d4d6cc7884ed6709f1a2a1af0f713382a4438ec2ea3a70d4d7ff386573563c3a75dbbd269fce9782620826ddac201000000010000000000000000000000910000001c0000004c0000006d000000810000008500000089000000897721e9016864141a8b982a48217f66ef318ce598aa31842cddaaebe3cd7feab17050022afa6c2123aba39938fe4142027ffd6a6a231561f2afe5878b1c743323b34263d16787130b1815fe35649b0bf58af204ac5d7cb8815a6c53a50b72d01e729d3b2201000000010000000000000000000000910000001c0000004c0000006d00000081000000850000008900000098eef09a3927acb225191101a1d9aa85775fdcdc87b9ba36898f6c132b485d66aef91c0f51cda331be4f985c3be6761c0232c489c23b1207107e9a24648c1e4754a8c1c0b38db96df57a526201035058cbf4cc1652dcec2e5de9ce6fb1b6f9fa9456e957f1010000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file diff --git a/devtools/metadata-cli/input.example.toml b/devtools/metadata-cli/input.example.toml index 004c87f65..9f59009f2 100644 --- a/devtools/metadata-cli/input.example.toml +++ b/devtools/metadata-cli/input.example.toml @@ -1,21 +1,18 @@ [[verifier_list]] bls_pub_key = "0xa26e3fe1cf51bd4822072c61bdc315ac32e3d3c2e2484bb92942666399e863b4bf56cf2926383cc706ffc15dfebc85c6" pub_key = "0x031ddc35212b7fc7ff6685b17d91f77c972535aee5c7ae5684d3e72b986f08834b" -address = "0x8ab0cf264df99d83525e9e11c7e4db01558ae1b1" propose_weight = "0x1" vote_weight = 1 [[verifier_list]] bls_pub_key = "0x80310fa9df724b5603d283b472ed3bf85254a8a4ceda8a274b421f6cf2be1d9184267cdfe9a199d36ff14e57668a55d0" pub_key = "0x02b77c74eb68af3d4d6cc7884ed6709f1a2a1af0f713382a4438ec2ea3a70d4d7f" -address = "0xf386573563c3a75dbbd269fce9782620826ddac2" propose_weight = 1 vote_weight = 1 [[verifier_list]] bls_pub_key = "0x897721e9016864141a8b982a48217f66ef318ce598aa31842cddaaebe3cd7feab17050022afa6c2123aba39938fe4142" pub_key = "0x027ffd6a6a231561f2afe5878b1c743323b34263d16787130b1815fe35649b0bf5" -address = "0x8af204ac5d7cb8815a6c53a50b72d01e729d3b22" propose_weight = 1 vote_weight = "0x01" diff --git a/devtools/metadata-cli/src/main.rs b/devtools/metadata-cli/src/main.rs index e13bac304..33228dc04 100644 --- a/devtools/metadata-cli/src/main.rs +++ b/devtools/metadata-cli/src/main.rs @@ -3,10 +3,10 @@ use std::path::PathBuf; use anyhow::{Context, Result}; use axon_types::{ basic::{Byte33, Byte48, Identity, Uint32, Uint64}, - metadata::{Metadata, MetadataCellData, MetadataList, ValidatorList}, + metadata::{Metadata, MetadataCellData, MetadataCellDataReader, MetadataList, ValidatorList}, }; use clap::{Parser, Subcommand}; -use molecule::prelude::{Builder, Entity}; +use molecule::prelude::{Builder, Entity, Reader}; use serde::{Deserialize, Serialize}; use serde_with::{serde_as, PickFirst}; @@ -15,7 +15,6 @@ use serde_helpers::{HexBytes, HexU32, HexU64}; #[serde_as] #[derive(Serialize, Deserialize)] -#[serde(deny_unknown_fields)] pub struct Validator { #[serde_as(as = "HexBytes")] pub bls_pub_key: [u8; 48], @@ -23,10 +22,6 @@ pub struct Validator { #[serde_as(as = "HexBytes")] pub pub_key: [u8; 33], - #[serde_as(as = "HexBytes")] - #[serde(default)] - pub address: [u8; 20], - #[serde_as(deserialize_as = "PickFirst<(_, HexU64)>")] #[serde(default)] pub propose_count: u64, @@ -42,10 +37,12 @@ pub struct Validator { impl From for axon_types::metadata::Validator { fn from(value: Validator) -> Self { + let address = + axon_protocol::types::Address::from_pubkey_bytes(value.pub_key.as_slice()).unwrap(); Self::new_builder() - .bls_pub_key(Byte48::from_slice(&value.bls_pub_key).unwrap()) - .pub_key(Byte33::from_slice(&value.pub_key).unwrap()) - .address(Identity::from_slice(&value.address).unwrap()) + .bls_pub_key(Byte48::from_slice(value.bls_pub_key.as_slice()).unwrap()) + .pub_key(Byte33::from_slice(value.pub_key.as_slice()).unwrap()) + .address(Identity::from_slice(address.as_slice()).unwrap()) .propose_count(Uint64::from_slice(&value.propose_count.to_le_bytes()).unwrap()) .propose_weight(Uint32::from_slice(&value.propose_weight.to_le_bytes()).unwrap()) .vote_weight(Uint32::from_slice(&value.vote_weight.to_le_bytes()).unwrap()) @@ -53,6 +50,22 @@ impl From for axon_types::metadata::Validator { } } +impl From<&axon_types::metadata::ValidatorReader<'_>> for Validator { + fn from(value: &axon_types::metadata::ValidatorReader) -> Self { + Self { + bls_pub_key: value.bls_pub_key().as_slice().try_into().unwrap(), + propose_count: u64::from_le_bytes( + value.propose_count().as_slice().try_into().unwrap(), + ), + propose_weight: u32::from_le_bytes( + value.propose_weight().as_slice().try_into().unwrap(), + ), + pub_key: value.pub_key().as_slice().try_into().unwrap(), + vote_weight: u32::from_le_bytes(value.vote_weight().as_slice().try_into().unwrap()), + } + } +} + pub fn metadata_cell_data_with_validators(vs: ValidatorList) -> MetadataCellData { MetadataCellData::new_builder() .metadata( @@ -83,12 +96,14 @@ struct Cli { #[derive(Subcommand)] enum Command { GetData(GetData), + ParseData(ParseData), } impl Command { fn run(self) -> Result<()> { match self { Command::GetData(g) => g.run(), + Command::ParseData(p) => p.run(), } } } @@ -145,6 +160,56 @@ impl GetData { } } +#[derive(Parser)] +struct ParseData { + #[arg(short, long)] + input: PathBuf, + #[arg(short, long)] + output: Option, +} + +impl ParseData { + fn run(self) -> Result<()> { + let input = std::fs::read_to_string(self.input).context("read input file")?; + let mut output: Box = if let Some(o) = self.output { + Box::new( + std::fs::OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(o) + .context("open output file")?, + ) + } else { + Box::new(std::io::stdout()) + }; + + let input = input.trim(); + let input = input.strip_prefix("0x").unwrap_or(input); + let input = hex::decode(input).context("decoding input")?; + + let data = MetadataCellDataReader::from_slice(&input) + .context("decoding input as MetadataCellData")?; + + if data.metadata().len() > 1 { + eprintln!("Only showing the first metadata"); + } + let metadata = data.metadata().get(0).context("no metadata")?; + + let result = Input { + validators: metadata.validators().iter().map(|v| (&v).into()).collect(), + }; + + let result = toml::to_string_pretty(&result).context("serializing result")?; + + output + .write_all(result.as_bytes()) + .context("writing output")?; + + Ok(()) + } +} + fn main() -> Result<()> { Cli::parse().command.run() } @@ -154,7 +219,7 @@ mod tests { use anyhow::{Context, Result}; use clap::Parser; - use super::GetData; + use super::{GetData, ParseData}; #[test] fn test_get_data() -> Result<()> { @@ -187,4 +252,14 @@ mod tests { Ok(()) } + + #[test] + fn test_parse_data() -> Result<()> { + ParseData::parse_from([ + "parse-data", + "-i", + concat!(env!("CARGO_MANIFEST_DIR"), "/data.example.hex"), + ]) + .run() + } }