diff --git a/.github/workflows/build_image_ghcr.yml b/.github/workflows/build_image_ghcr.yml index 49032aef4..917dc7c5d 100644 --- a/.github/workflows/build_image_ghcr.yml +++ b/.github/workflows/build_image_ghcr.yml @@ -103,7 +103,7 @@ jobs: - name: Modify the Axon image of in devtools/chain/docker-compose.yml env: AXON_IMAGE: "${{ needs.build-amd64-image-to-ghcr.outputs.image_name }}:${{ needs.build-amd64-image-to-ghcr.outputs.image_tag }}" - uses: mikefarah/yq@v4.40.4 + uses: mikefarah/yq@v4.40.5 with: cmd: yq -i '.services.axon.image = "${{ env.AXON_IMAGE }}"' 'devtools/chain/docker-compose.yml' diff --git a/.github/workflows/chaos.yml b/.github/workflows/chaos.yml deleted file mode 100644 index 01a98712d..000000000 --- a/.github/workflows/chaos.yml +++ /dev/null @@ -1,109 +0,0 @@ -name: Chaos CI -on: - workflow_dispatch: - inputs: - dispatch: - type: string - description: "Dispatch contains pr context that want to trigger chaos test" - required: true - -jobs: - build: - if: contains(github.event_name, 'workflow_dispatch') - runs-on: self-hosted - environment: chaos - outputs: - output-sha: ${{ steps.escape_multiple_lines_test_inputs.outputs.sha }} - steps: - - name: Generate axon-bot token - if: contains(github.event_name, 'workflow_dispatch') && - github.repository_owner == 'axonweb3' && github.event.inputs.dispatch != 'regression' - id: generate_axon_bot_token - uses: wow-actions/use-app-token@v2 - with: - app_id: ${{ secrets.AXON_BOT_APP_ID }} - private_key: ${{ secrets.AXON_BOT_PRIVATE_KEY }} - - name: Event is dispatch - if: contains(github.event_name, 'workflow_dispatch') && - github.repository_owner == 'axonweb3' && github.event.inputs.dispatch != 'regression' - uses: actions/github-script@v7 - id: get_sha - with: - github-token: ${{ steps.generate_axon_bot_token.outputs.BOT_TOKEN }} - script: | - const dispatch = JSON.parse(`${{ github.event.inputs.dispatch }}`); - const pr = ( - await github.rest.pulls.get({ - owner: dispatch.repo.owner, - repo: dispatch.repo.repo, - pull_number: dispatch.issue.number, - }) - ).data.head; - github.rest.repos.createCommitStatus({ - state: 'pending', - owner: dispatch.repo.owner, - repo: dispatch.repo.repo, - context: '${{ github.workflow }}', - sha: pr.sha, - target_url: 'https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}' - }) - const ref= pr.ref; - const pr_number= dispatch.issue.number; - const sha= pr.sha; - return { ref,pr_number,sha} - - name: Escape multiple lines test inputs - if: contains(github.event_name, 'workflow_dispatch') && - github.repository_owner == 'axonweb3' && github.event.inputs.dispatch != 'regression' - id: escape_multiple_lines_test_inputs - run: | - ref=$(echo "${{ steps.get_sha.outputs.result }}" | awk -F ':' '{print $2}'| awk -F ',' '{print $1}') - pr_number=$(echo "${{ steps.get_sha.outputs.result }}" | awk -F ':' '{print $3}'| awk -F ',' '{print $1}') - sha=$(echo "${{ steps.get_sha.outputs.result }}" | awk -F ':' '{print $4}'| awk -F '}' '{print $1}') - echo "ref=$ref" >> $GITHUB_OUTPUT - echo "pr_number=$pr_number" >> $GITHUB_OUTPUT - echo "sha=$sha" >> $GITHUB_OUTPUT - - - name: Git checkout - uses: actions/checkout@v4 - with: - ref: ${{ steps.escape_multiple_lines_test_inputs.outputs.ref || 'main' }} - - - name: Build Axon - run: | - cd /home/ckb/axon-devops/axon-image/ - ansible-playbook build.yml --tags build -e axon_branch=${{ steps.escape_multiple_lines_test_inputs.outputs.ref }} -e pr_number=${{ steps.escape_multiple_lines_test_inputs.outputs.pr_number }} - - - name: Run chaos - run: | - cd /home/ckb/axon-devops/axon-chaos/axon-chaos-integration - yarn install - node index.js ${{ secrets.CHAOS_URL }} - - finally: - name: Finally - needs: [ build ] - if: always() && contains(github.event_name, 'workflow_dispatch') && - github.event.inputs.dispatch != 'regression' && github.repository_owner == 'axonweb3' - runs-on: ubuntu-latest - steps: - - name: Generate axon-bot token - id: generate_axon_bot_token - uses: wow-actions/use-app-token@v2 - with: - app_id: ${{ secrets.AXON_BOT_APP_ID }} - private_key: ${{ secrets.AXON_BOT_PRIVATE_KEY }} - - if: contains(join(needs.*.result, ';'), 'failure') || contains(join(needs.*.result, ';'), 'cancelled') - run: exit 1 - - uses: actions/github-script@v7 - if: ${{ always() }} - with: - github-token: ${{ steps.generate_axon_bot_token.outputs.BOT_TOKEN }} - script: | - github.rest.repos.createCommitStatus({ - state: '${{ job.status }}', - owner: context.repo.owner, - repo: context.repo.repo, - context: '${{ github.workflow }}', - sha: '${{ needs.build.outputs.output-sha }}', - target_url: 'https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}' - }) diff --git a/.github/workflows/hardfork_test.yml b/.github/workflows/hardfork_test.yml index ab28b94e1..a431ff22c 100644 --- a/.github/workflows/hardfork_test.yml +++ b/.github/workflows/hardfork_test.yml @@ -74,15 +74,15 @@ jobs: EOF timeout-minutes: 1 - - name: Checkout axonweb3/axon-hardfork-test + - name: Checkout axonweb3/system-contract-test uses: actions/checkout@v4 with: - repository: axonweb3/axon-hardfork-test - ref: b1f768de8be10604cad882474c0dcfa19c0a93ea - path: axon-hardfork-test + repository: axonweb3/system-contract-test + ref: 69293ac366991cf5830ab8366a85d72449daeadc + path: system-contract-test - name: Choose network - working-directory: axon-hardfork-test + working-directory: system-contract-test run: | node_ids=(1 2 3 4) random_value=$(( (RANDOM % ${#node_ids[@]}) + 1 )) @@ -93,20 +93,26 @@ jobs: grep "defaultNetwork" hardhat.config.ts - name: Run test cases before hardfork - working-directory: axon-hardfork-test + working-directory: system-contract-test run: | npm install npx hardhat test --grep "deploy a normal contract" npx hardhat test --grep "deploy a big contract larger than max_contract_limit" npx hardhat test --grep "check hardfork info before hardfork" + - name: Run test cases to verify proof + working-directory: system-contract-test + run: | + npx hardhat test --grep "transfer demo" + npx hardhat test test/verifyProof.ts --network proof + - name: Hardfork - working-directory: axon-hardfork-test + working-directory: system-contract-test run: | bash hardfork.sh ../ - name: Run test cases after hardfork - working-directory: axon-hardfork-test + working-directory: system-contract-test run: | npx hardhat test --grep "check hardfork info after hardfork" npx hardhat test --grep "update max_contract_limit" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f0151cd2e..1f18b1399 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -138,22 +138,3 @@ jobs: asset_name: axon_${{ needs.version.outputs.tag }}_${{ matrix.REL_PKG }} asset_path: ${{ github.workspace }}/axon_${{ needs.version.outputs.tag }}_${{ matrix.REL_PKG }} asset_content_type: application/octet-stream - - trigger-build-docker-image: - runs-on: ubuntu-22.04 - needs: - - version - steps: - - uses: actions/checkout@v4 - - name: Generate axon-bot token - id: generate_axon_bot_token - uses: wow-actions/use-app-token@v2 - with: - app_id: ${{ secrets.AXON_BOT_APP_ID }} - private_key: ${{ secrets.AXON_BOT_PRIVATE_KEY }} - - name: Invoke build docker image with inputs - uses: aurelien-baudet/workflow-dispatch@v2 - with: - workflow: Build docker image - token: ${{ secrets.GITHUB_TOKEN }} - inputs: '{ "dispatch": "${{ needs.version.outputs.tag }}" }' diff --git a/Cargo.lock b/Cargo.lock index 7a375eab7..93d628652 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,15 +120,6 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - [[package]] name = "anstream" version = "0.6.4" @@ -284,20 +275,6 @@ dependencies = [ "core-run", ] -[[package]] -name = "axon-keypair" -version = "0.2.1" -dependencies = [ - "axon-protocol", - "clap 2.34.0", - "ophelia", - "ophelia-blst", - "rand 0.7.3", - "serde", - "serde_json", - "tentacle-secio", -] - [[package]] name = "axon-protocol" version = "0.1.0" @@ -1392,22 +1369,6 @@ dependencies = [ "libloading", ] -[[package]] -name = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "ansi_term", - "atty", - "bitflags 1.3.2", - "strsim 0.8.0", - "textwrap 0.11.0", - "unicode-width", - "vec_map", - "yaml-rust 0.3.5", -] - [[package]] name = "clap" version = "3.2.25" @@ -1420,9 +1381,9 @@ dependencies = [ "clap_lex 0.2.4", "indexmap 1.9.3", "once_cell", - "strsim 0.10.0", + "strsim", "termcolor", - "textwrap 0.16.0", + "textwrap", ] [[package]] @@ -1444,7 +1405,7 @@ dependencies = [ "anstream", "anstyle", "clap_lex 0.5.0", - "strsim 0.10.0", + "strsim", ] [[package]] @@ -1815,9 +1776,11 @@ dependencies = [ name = "core-cli" version = "0.1.0" dependencies = [ + "anyhow", "axon-protocol", "clap 4.4.6", "common-config-parser", + "common-crypto", "common-logger", "common-version", "core-run", @@ -1825,6 +1788,7 @@ dependencies = [ "serde", "serde_json", "tempfile", + "tentacle-secio", "thiserror", ] @@ -2298,7 +2262,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim 0.10.0", + "strsim", "syn 1.0.109", ] @@ -6573,7 +6537,7 @@ dependencies = [ "indexmap 1.9.3", "ryu", "serde", - "yaml-rust 0.4.5", + "yaml-rust", ] [[package]] @@ -6812,12 +6776,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "913e7b03d63752f6cdd2df77da36749d82669904798fe8944b9ec3d23f159905" -[[package]] -name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - [[package]] name = "strsim" version = "0.10.0" @@ -7119,15 +7077,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - [[package]] name = "textwrap" version = "0.16.0" @@ -7809,12 +7758,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - [[package]] name = "version_check" version = "0.9.4" @@ -8209,12 +8152,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "yaml-rust" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" - [[package]] name = "yaml-rust" version = "0.4.5" diff --git a/Cargo.toml b/Cargo.toml index d9fc2b537..82f329a7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,6 @@ members = [ "core/storage", "devtools/abi-generator", "devtools/axon-tools", - "devtools/keypair", "protocol", ] diff --git a/core/cli/Cargo.toml b/core/cli/Cargo.toml index efb23f76f..1fa8b9d18 100644 --- a/core/cli/Cargo.toml +++ b/core/cli/Cargo.toml @@ -5,14 +5,17 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +anyhow = "1.0" clap = { version = "4.4", features = ["cargo", "string", "derive"] } semver = "1.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" tempfile = "3.6" +tentacle-secio = "0.6" thiserror = "1.0" common-config-parser = { path = "../../common/config-parser" } +common-crypto ={ path = "../../common/crypto" } common-logger = { path = "../../common/logger" } common-version = { path = "../../common/version" } core-run = { path = "../../core/run" } diff --git a/core/cli/README.md b/core/cli/README.md new file mode 100644 index 000000000..ef8a591d5 --- /dev/null +++ b/core/cli/README.md @@ -0,0 +1,102 @@ +# Axon CLI + +Axon CLI is a command line tool for Axon framework. It is included in the Axon binary with the command of `cargo build --release`. + +## Usage + +### Generate Keypair + +```bash +./target/release/axon generate-keypair -n 1 -p path-to-save-private-keys +``` + +Example Output: + +```bash +$ cargo run -- -n 1 -p path-to-save-private-keys +{ + "keypairs": [ + { + "index": 0, + "net_private_key": "0x0000000000000000000000000000000000000000000000000000000000000000", + "public_key": "0x020044def250d1d27c0f7c0eeee6c8b964756d5ad7936fcefaf3f086245ddb9c9c", + "address": "0x83fec4b12b26a70195ccabb67ce0cd692856eaf1", + "peer_id": "QmbZEzvonMiPiioRpYeVWxngjN42FHC3EHXjeo2C7o2NDZ", + "bls_private_key": "0x1111111111111111111111111111111111111111111111111111111111111111", + "bls_public_key": "0x81ca54f01e3b433c209ae1d165e6362669e13170f89712dbc52c3572901d025ecc206a43c4b25f58388189f74587a7d" + } + ] +} +``` + +The arguments are described in the following table: + +| name | short | default value | +|--|--|--| +| number | n | 4 | +| private-key-path | p | current_path/free-space/ | + +### Update Config and Spec File + +First, update the `validator_list` in the [chain-spec](../../devtools/chain/specs/single_node/chain-spec.toml) file. Replace the `bls_pub_key`, `pub_key` and `address` with the value generated by the keypair generator, for example: + +```toml +[[params.verifier_list]] +bls_pub_key = "0x81ca54f01e3b433c209ae1d165e6362669e13170f89712dbc52c3572901d025ecc206a43c4b25f58388189f74587a7d" +pub_key = "0x020044def250d1d27c0f7c0eeee6c8b964756d5ad7936fcefaf3f086245ddb9c9c" +address = "0x83fec4b12b26a70195ccabb67ce0cd692856eaf1" +propose_weight = 1 +vote_weight = 1 +``` + +Then, update the `bootstraps` in the [config](../../devtools/chain/config.toml) file. Fill the generated `peer_id` to the `multi_address` For example: + +```toml +[[network.bootstraps]] +multi_address = "/ip4/127.0.0.1/tcp/8001/p2p/QmbZEzvonMiPiioRpYeVWxngjN42FHC3EHXjeo2C7o2NDZ" +``` + +Finally, set the `net_privkey_file` and `bls_privkey_file` with the generated private key file path in [config](../../devtools/chain/config.toml) file. + +### Recover Public Key and Peer ID + +If you forget your public key and peer id, you can recover them from the private key file. + +```bash +./target/release/axon recover-keypair -n path-of-net-private-key -b path-of-bls-private-key +``` + +The arguments are described in the following table: + +| name | short | default value | +|--|--|--| +| net-path | n | - | +| bls-path | b | - | + +### Init Chain + +After the config and spec file are updated, you can initialize the chain with the following command: + +```bash +./target/release/axon init -c path-of-config-file -s path-of-chain-spec-file +``` +The console will print the execution result of genesis block. The arguments are described in the following table: + +| name | short | default value | +|--|--|--| +| config | c | - | +| chain-spec | s | - | + +### Run Node + +Finally, you can run the node with the following command: + +```bash +./target/release/axon run -c path-of-config-file +``` + +The arguments are described in the following table: + +| name | short | default value | +|--|--|--| +| config | c | - | diff --git a/core/cli/src/args/generate_keypair.rs b/core/cli/src/args/generate_keypair.rs new file mode 100644 index 000000000..b2384a73b --- /dev/null +++ b/core/cli/src/args/generate_keypair.rs @@ -0,0 +1,159 @@ +use std::path::{Path, PathBuf}; +use std::{fs::File, io::Write}; + +use clap::Parser; +use serde::Serialize; + +use common_crypto::{BlsPrivateKey, PrivateKey, PublicKey, Secp256k1PrivateKey, ToBlsPublicKey}; +use protocol::rand::rngs::OsRng; +use protocol::types::{Address, Bytes, Hex}; +use tentacle_secio::SecioKeyPair; + +use crate::error::{Error, Result}; + +#[derive(Parser, Debug)] +#[command(about = "Initialize new axon data directory")] +pub struct GenerateKeypairArgs { + #[arg( + short = 'n', + long = "number", + value_name = "NUMBER", + help = "The number of keypairs to generate.", + default_value = "1" + )] + pub num: usize, + #[arg( + short = 'p', + long = "path", + value_name = "PRIVATE_KEY_PATH", + help = "The path to store the generated private key binary.", + default_value = "free-space" + )] + pub path: String, +} + +impl GenerateKeypairArgs { + pub(crate) fn execute(self) -> Result<()> { + let Self { num, path } = self; + let mut keypairs = Vec::with_capacity(num); + let path = Path::new(&path); + + for i in 0..num { + let key_pair = Keypair::generate(i)?; + write_private_keys( + path, + key_pair.net_private_key.as_bytes(), + key_pair.bls_private_key.as_bytes(), + i, + )?; + keypairs.push(Keypair::generate(i)?); + } + + println!( + "{}", + serde_json::to_string_pretty(&Output { keypairs }).unwrap() + ); + + Ok(()) + } +} + +#[derive(Serialize, Clone, Debug)] +pub struct Keypair { + pub index: usize, + pub net_private_key: Hex, + pub public_key: Hex, + pub address: Address, + pub peer_id: Hex, + pub bls_private_key: Hex, + pub bls_public_key: Hex, +} + +impl Keypair { + pub(crate) fn generate(i: usize) -> Result { + let bls_seckey = BlsPrivateKey::generate(&mut OsRng).to_bytes(); + let net_seckey = Secp256k1PrivateKey::generate(&mut OsRng).to_bytes(); + Self::from_private_keys(net_seckey, bls_seckey, i) + } + + pub(crate) fn from_private_keys( + net_seckey: Bytes, + bls_seckey: Bytes, + i: usize, + ) -> Result { + let secio_keypair = SecioKeyPair::secp256k1_raw_key(&net_seckey) + .map_err(|e| Error::Crypto(e.to_string()))?; + let pubkey = secio_keypair.public_key().inner(); + + let bls_priv_key = BlsPrivateKey::try_from(bls_seckey.as_ref()) + .map_err(|e| Error::Crypto(e.to_string()))?; + let bls_pub_key = bls_priv_key.pub_key(&String::new()); + + Ok(Keypair { + index: i, + net_private_key: Hex::encode(&net_seckey), + public_key: Hex::encode(&pubkey), + address: Address::from_pubkey_bytes(pubkey).map_err(Error::Running)?, + peer_id: Hex::encode(secio_keypair.public_key().peer_id().to_base58()), + bls_private_key: Hex::encode(&bls_seckey), + bls_public_key: Hex::encode(bls_pub_key.to_bytes()), + }) + } + + #[cfg(test)] + pub(crate) fn check(&self) { + use common_crypto::{BlsSignatureVerify, HashValue, ToPublicKey}; + use tentacle_secio::KeyProvider; + + let another_pubkey = Secp256k1PrivateKey::try_from(self.net_private_key.as_ref()) + .unwrap() + .pub_key(); + assert_eq!(self.public_key, Hex::encode(another_pubkey.to_bytes())); + assert_ne!(self.net_private_key, self.bls_private_key); + + let msg = HashValue::from_bytes_unchecked(protocol::types::Hasher::digest("axon").0); + let net_priv_key = SecioKeyPair::secp256k1_raw_key(self.net_private_key.as_ref()).unwrap(); + let bls_priv_key = BlsPrivateKey::try_from(self.bls_private_key.as_ref()).unwrap(); + let net_sig = net_priv_key.sign_ecdsa(&msg).unwrap(); + let bls_sig = bls_priv_key.sign_message(&msg); + let net_pub_key = net_priv_key.public_key(); + let bls_pub_key = bls_priv_key.pub_key(&String::new()); + + assert!(bls_sig.verify(&msg, &bls_pub_key, &String::new()).is_ok()); + assert!(net_priv_key.verify_ecdsa(net_pub_key.inner_ref(), &msg, net_sig)); + } +} + +#[derive(Serialize, Clone, Debug)] +struct Output { + keypairs: Vec, +} + +fn write_private_keys(path: &Path, net_key: Bytes, bls_key: Bytes, index: usize) -> Result<()> { + let write = |path: PathBuf, data: Bytes| -> Result<()> { + let mut file = File::create(path).map_err(Error::WritingPrivateKey)?; + file.write_all(&data).map_err(Error::WritingPrivateKey)?; + + Ok(()) + }; + + let mut bls_key_path = path.to_path_buf(); + bls_key_path.push(format!("bls_{}.key", index)); + let mut net_key_path = path.to_path_buf(); + net_key_path.push(format!("net_{}.key", index)); + + write(bls_key_path, bls_key)?; + write(net_key_path, net_key)?; + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_generate_keypair() { + let keypair = Keypair::generate(1).unwrap(); + keypair.check(); + } +} diff --git a/core/cli/src/args/mod.rs b/core/cli/src/args/mod.rs index eabc31743..3aa38c1e4 100644 --- a/core/cli/src/args/mod.rs +++ b/core/cli/src/args/mod.rs @@ -1,3 +1,5 @@ +pub(crate) mod generate_keypair; pub(crate) mod hardfork; pub(crate) mod init; +pub(crate) mod recover_keypair; pub(crate) mod run; diff --git a/core/cli/src/args/recover_keypair.rs b/core/cli/src/args/recover_keypair.rs new file mode 100644 index 000000000..be3241c2f --- /dev/null +++ b/core/cli/src/args/recover_keypair.rs @@ -0,0 +1,67 @@ +use std::{fs::File, io::Read, path::PathBuf}; + +use clap::Parser; + +use protocol::types::Bytes; + +use crate::args::generate_keypair::Keypair; +use crate::error::{Error, Result}; + +#[derive(Parser, Debug)] +#[command(about = "Initialize new axon data directory")] +pub struct RecoverKeypairArgs { + #[arg( + short = 'n', + long = "net_path", + value_name = "NET_PRIVATE_KEY_PATH", + help = "The path to store the net private key binary." + )] + pub net_private_key_path: String, + #[arg( + short = 'b', + long = "bls_path", + value_name = "BLS_PRIVATE_KEY_PATH", + help = "The path to store the bls private key binary." + )] + pub bls_private_key_path: String, +} + +impl RecoverKeypairArgs { + pub(crate) fn execute(self) -> Result<()> { + let Self { + net_private_key_path, + bls_private_key_path, + } = self; + let net_private_key = read_private_key(&PathBuf::from(net_private_key_path))?; + let bls_private_key = read_private_key(&PathBuf::from(bls_private_key_path))?; + + let output = Keypair::from_private_keys(net_private_key, bls_private_key, 0)?; + println!("{}", serde_json::to_string_pretty(&output).unwrap()); + + Ok(()) + } +} + +fn read_private_key(path: &PathBuf) -> Result { + let mut file = File::open(path).map_err(Error::ReadingPrivateKey)?; + let mut buf = Vec::new(); + file.read_to_end(&mut buf) + .map_err(Error::ReadingPrivateKey)?; + Ok(buf.into()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_read_binary_priv_keys() { + let net_key_path = "../../devtools/chain/net.key"; + let bls_key_path = "../../devtools/chain/bls.key"; + let net_private_key = read_private_key(&PathBuf::from(net_key_path)).unwrap(); + let bls_private_key = read_private_key(&PathBuf::from(bls_key_path)).unwrap(); + Keypair::from_private_keys(net_private_key, bls_private_key, 1) + .unwrap() + .check(); + } +} diff --git a/core/cli/src/error.rs b/core/cli/src/error.rs index 55ad7724d..edf672feb 100644 --- a/core/cli/src/error.rs +++ b/core/cli/src/error.rs @@ -11,14 +11,23 @@ pub enum Error { // Boxing so the error type isn't too large (clippy::result-large-err). #[error(transparent)] CheckingVersion(Box), + #[error("reading data version: {0}")] ReadingVersion(#[source] io::Error), #[error("writing data version: {0}")] WritingVersion(#[source] io::Error), + #[error("reading private key: {0}")] + ReadingPrivateKey(#[source] io::Error), + #[error("writing private key: {0}")] + WritingPrivateKey(#[source] io::Error), + #[error(transparent)] Running(ProtocolError), + #[error("crypto error: {0}")] + Crypto(String), + #[error("internal error: {0}")] Internal(String), } diff --git a/core/cli/src/lib.rs b/core/cli/src/lib.rs index 58f2b149e..5b9370b12 100644 --- a/core/cli/src/lib.rs +++ b/core/cli/src/lib.rs @@ -2,7 +2,10 @@ mod args; mod error; pub(crate) mod utils; -pub use args::{hardfork::HardforkArgs, init::InitArgs, run::RunArgs}; +pub use args::{ + generate_keypair::GenerateKeypairArgs, hardfork::HardforkArgs, init::InitArgs, + recover_keypair::RecoverKeypairArgs, run::RunArgs, +}; pub use error::{CheckingVersionError, Error, Result}; use clap::{CommandFactory as _, FromArgMatches as _, Parser, Subcommand}; @@ -22,6 +25,8 @@ enum Commands { Init(InitArgs), Run(RunArgs), Hardfork(HardforkArgs), + GenerateKeypair(GenerateKeypairArgs), + RecoverKeypair(RecoverKeypairArgs), } pub struct AxonCli { @@ -62,6 +67,8 @@ impl AxonCli { Commands::Init(args) => args.execute(kernel_version), Commands::Run(args) => args.execute(application_version, kernel_version, key_provider), Commands::Hardfork(args) => args.execute(), + Commands::GenerateKeypair(args) => args.execute(), + Commands::RecoverKeypair(args) => args.execute(), } } } diff --git a/core/mempool/src/adapter/mod.rs b/core/mempool/src/adapter/mod.rs index 866faa5c9..01745c18d 100644 --- a/core/mempool/src/adapter/mod.rs +++ b/core/mempool/src/adapter/mod.rs @@ -1,6 +1,6 @@ pub mod message; -use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicUsize, Ordering}; use std::{collections::HashMap, error::Error, marker::PhantomData, sync::Arc, time::Duration}; use dashmap::DashMap; @@ -11,6 +11,7 @@ use futures::{ use log::{debug, error}; use parking_lot::Mutex; +use protocol::constants::{MAX_GAS_LIMIT, MIN_TRANSACTION_GAS_LIMIT}; use protocol::traits::{ Context, Gossip, Interoperation, MemPoolAdapter, PeerTrust, Priority, ReadOnlyStorage, Rpc, TrustFeedback, @@ -122,7 +123,6 @@ pub struct DefaultMemPoolAdapter { trie_db: Arc, addr_nonce: DashMap, - gas_limit: AtomicU64, max_tx_size: AtomicUsize, chain_id: u64, @@ -146,7 +146,6 @@ where storage: Arc, trie_db: Arc, chain_id: u64, - gas_limit: u64, max_tx_size: usize, broadcast_txs_size: usize, broadcast_txs_interval: u64, @@ -168,7 +167,6 @@ where trie_db, addr_nonce: DashMap::new(), - gas_limit: AtomicU64::new(gas_limit), max_tx_size: AtomicUsize::new(max_tx_size), chain_id, @@ -253,7 +251,25 @@ where fn verify_gas_limit(&self, ctx: Context, stx: &SignedTransaction) -> ProtocolResult<()> { let gas_limit_tx = stx.transaction.unsigned.gas_limit(); - if gas_limit_tx > &U64::from(self.gas_limit.load(Ordering::Acquire)) { + if gas_limit_tx < &(MIN_TRANSACTION_GAS_LIMIT.into()) { + if ctx.is_network_origin_txs() { + self.network.report( + ctx, + TrustFeedback::Bad(format!( + "Mempool under gas limit of tx {:#x}", + stx.transaction.hash + )), + ); + } + + return Err(MemPoolError::UnderGasLimit { + tx_hash: stx.transaction.hash, + gas_limit_tx: gas_limit_tx.low_u64(), + } + .into()); + } + + if gas_limit_tx > &(MAX_GAS_LIMIT.into()) { if ctx.is_network_origin_txs() { self.network.report( ctx, @@ -263,10 +279,10 @@ where )), ); } + return Err(MemPoolError::ExceedGasLimit { - tx_hash: stx.transaction.hash, - gas_limit_tx: gas_limit_tx.low_u64(), - gas_limit_config: self.gas_limit.load(Ordering::Acquire), + tx_hash: stx.transaction.hash, + gas_limit_tx: gas_limit_tx.low_u64(), } .into()); } @@ -474,10 +490,9 @@ where &self, _context: Context, _state_root: MerkleRoot, - cycles_limit: u64, + _cycles_limit: u64, max_tx_size: u64, ) { - self.gas_limit.store(cycles_limit, Ordering::Release); self.max_tx_size .store(max_tx_size as usize, Ordering::Release); self.addr_nonce.clear(); diff --git a/core/mempool/src/lib.rs b/core/mempool/src/lib.rs index 308ee73f6..97165c2a7 100644 --- a/core/mempool/src/lib.rs +++ b/core/mempool/src/lib.rs @@ -391,15 +391,23 @@ pub enum MemPoolError { }, #[display( - fmt = "Tx: {:?} exceeds cycle limit, tx: {}, config: {}", + fmt = "Tx: {:?} exceeds 30000000, tx gas limit {}", tx_hash, - gas_limit_tx, - gas_limit_config + gas_limit_tx )] ExceedGasLimit { - tx_hash: Hash, - gas_limit_config: u64, - gas_limit_tx: u64, + tx_hash: Hash, + gas_limit_tx: u64, + }, + + #[display( + fmt = "Tx: {:?} gas price is less than 21000, tx gas limit {}", + tx_hash, + gas_limit_tx + )] + UnderGasLimit { + tx_hash: Hash, + gas_limit_tx: u64, }, #[display(fmt = "Tx nonce {} is invalid current nonce {}", tx_nonce, current)] diff --git a/core/run/src/lib.rs b/core/run/src/lib.rs index f536c9ffd..05018cd6a 100644 --- a/core/run/src/lib.rs +++ b/core/run/src/lib.rs @@ -345,7 +345,6 @@ where Arc::clone(storage), Arc::clone(trie_db), current_header.chain_id, - current_header.gas_limit.low_u64(), config.pool_size as usize, config.broadcast_txs_size, config.broadcast_txs_interval, diff --git a/devtools/keypair/Cargo.toml b/devtools/keypair/Cargo.toml deleted file mode 100644 index ac72464d7..000000000 --- a/devtools/keypair/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "axon-keypair" -version = "0.2.1" -edition = "2021" -include = ["Cargo.toml", "src/*"] -license = "MIT" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -clap = { version = "2.33", features = ["yaml"] } -ophelia = "0.3" -ophelia-blst = "0.3" -protocol = { path = "../../protocol", package = "axon-protocol" } -rand = "0.7" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -tentacle-secio = "0.6" diff --git a/devtools/keypair/src/keypair.yml b/devtools/keypair/src/keypair.yml deleted file mode 100644 index fc49fcfb6..000000000 --- a/devtools/keypair/src/keypair.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: axon_keypair -version: "0.1" -about: a tool to generate keypairs for axon -author: axon Dev - -args: - - number: - help: Number of keypairs to generate - short: n - long: number - default_value: "4" - - - private_keys: - help: Generate keypairs from a given private key vector - short: p - long: private_keys - multiple: true - takes_value: true - - - common_ref: - help: common_ref for bls signature, it will be randomly generated if not passed - short: c - long: common_ref - default_value: "" diff --git a/devtools/keypair/src/main.rs b/devtools/keypair/src/main.rs deleted file mode 100644 index 8400b758d..000000000 --- a/devtools/keypair/src/main.rs +++ /dev/null @@ -1,77 +0,0 @@ -#[macro_use] -extern crate clap; - -use std::convert::TryFrom; -use std::default::Default; - -use clap::App; -use ophelia::{PrivateKey, PublicKey, ToBlsPublicKey}; -use ophelia_blst::BlsPrivateKey; -use protocol::codec::{hex_decode, hex_encode}; -use protocol::types::{Address, Bytes}; -use rand::rngs::OsRng; -use serde::Serialize; -use tentacle_secio::SecioKeyPair; - -#[derive(Default, Serialize, Debug)] -struct Keypair { - pub index: usize, - pub private_key: String, - pub public_key: String, - pub address: String, - pub peer_id: String, - pub bls_public_key: String, -} - -#[derive(Default, Serialize, Debug)] -struct Output { - pub common_ref: String, - pub keypairs: Vec, -} - -#[allow(clippy::needless_range_loop, clippy::uninlined_format_args)] -pub fn main() { - let yml = load_yaml!("keypair.yml"); - let m = App::from(yml).get_matches(); - let number = value_t!(m, "number", usize).unwrap(); - let priv_keys = values_t!(m.values_of("private_keys"), String).unwrap_or_default(); - let len = priv_keys.len(); - if len > number { - panic!("private keys length can not be larger than number"); - } - - let mut output = Output { - common_ref: add_0x(String::from("0")), - keypairs: vec![], - }; - - for i in 0..number { - let mut k = Keypair::default(); - let seckey = if i < len { - Bytes::from(hex_decode(&priv_keys[i]).expect("decode hex private key")) - } else { - BlsPrivateKey::generate(&mut OsRng).to_bytes() - }; - - let keypair = SecioKeyPair::secp256k1_raw_key(seckey.as_ref()).expect("secp256k1 keypair"); - let pubkey = keypair.public_key().inner(); - let address = Address::from_pubkey_bytes(pubkey.clone()).unwrap(); - - k.private_key = add_0x(hex_encode(seckey.as_ref())); - k.public_key = add_0x(hex_encode(pubkey)); - k.peer_id = keypair.public_key().peer_id().to_base58(); - k.address = add_0x(hex_encode(address.as_slice())); - - let priv_key = BlsPrivateKey::try_from(seckey.as_ref()).unwrap(); - let pub_key = priv_key.pub_key(&output.common_ref); - k.bls_public_key = add_0x(hex_encode(pub_key.to_bytes())); - k.index = i + 1; - output.keypairs.push(k); - } - let output_str = serde_json::to_string_pretty(&output).unwrap(); - println!("{}", output_str); -} - -fn add_0x(s: String) -> String { - "0x".to_owned() + &s -}