diff --git a/.github/workflows/axon-start-test.yml b/.github/workflows/axon-start-test.yml index d58ae11ec..c309b846d 100644 --- a/.github/workflows/axon-start-test.yml +++ b/.github/workflows/axon-start-test.yml @@ -60,7 +60,7 @@ jobs: - name: Archive logs if: failure() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: single-axon-node-logs path: | @@ -131,7 +131,7 @@ jobs: - name: Archive logs if: failure() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: multi-axon-nodes-logs path: | 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/coverage.yml b/.github/workflows/coverage.yml index 7a0c49e19..d68df338a 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -82,7 +82,7 @@ jobs: token: ${{secrets.CODECOV_TOKEN}} - name: archive code coverage results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: code-coverage-report path: cobertura.xml diff --git a/.github/workflows/hardfork_test.yml b/.github/workflows/hardfork_test.yml index ab28b94e1..91143244e 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" @@ -114,7 +120,7 @@ jobs: - name: Archive logs if: failure() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: multi-axon-nodes-logs path: | diff --git a/.github/workflows/openzeppelin_test_11.yml b/.github/workflows/openzeppelin_test_11.yml index 4818420f5..2813b5932 100644 --- a/.github/workflows/openzeppelin_test_11.yml +++ b/.github/workflows/openzeppelin_test_11.yml @@ -174,7 +174,7 @@ jobs: - name: Publish reports if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: jfoa-build-reports-${{ runner.os }} path: openzeppelin-contracts/mochawesome-report/ diff --git a/.github/workflows/openzeppelin_test_16_19.yml b/.github/workflows/openzeppelin_test_16_19.yml index 13a6ef1a8..d2f0d2f26 100644 --- a/.github/workflows/openzeppelin_test_16_19.yml +++ b/.github/workflows/openzeppelin_test_16_19.yml @@ -185,7 +185,7 @@ jobs: curl http://localhost:8000 -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params": [],"id":1}' - name: Publish reports if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: jfoa-build-reports-${{ runner.os }} path: openzeppelin-contracts/mochawesome-report/ diff --git a/.github/workflows/openzeppelin_test_1_5_and_12_15.yml b/.github/workflows/openzeppelin_test_1_5_and_12_15.yml index 6cbd0e8dd..4afd9bb1f 100644 --- a/.github/workflows/openzeppelin_test_1_5_and_12_15.yml +++ b/.github/workflows/openzeppelin_test_1_5_and_12_15.yml @@ -215,7 +215,7 @@ jobs: - name: Publish reports if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: jfoa-build-reports-${{ runner.os }} path: openzeppelin-contracts/mochawesome-report/ diff --git a/.github/workflows/openzeppelin_test_6_10.yml b/.github/workflows/openzeppelin_test_6_10.yml index dbe07b68f..8c3b5bdf8 100644 --- a/.github/workflows/openzeppelin_test_6_10.yml +++ b/.github/workflows/openzeppelin_test_6_10.yml @@ -191,7 +191,7 @@ jobs: curl http://localhost:8000 -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params": [],"id":1}' - name: Publish reports if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: jfoa-build-reports-${{ runner.os }} path: openzeppelin-contracts/mochawesome-report/ diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f0151cd2e..f67f4c3f6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -106,7 +106,7 @@ jobs: popd mv ${{ github.workspace }}/releases/axon_${{ needs.version.outputs.tag }}_${{ matrix.job.REL_PKG}} ${{ github.workspace }} - name: upload-zip-file - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: axon_${{ needs.version.outputs.tag }}_${{ matrix.job.REL_PKG }} path: axon_${{ needs.version.outputs.tag }}_${{ matrix.job.REL_PKG }} @@ -126,7 +126,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: Prepare - Download tar - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: axon_${{ needs.version.outputs.tag }}_${{ matrix.REL_PKG }} - name: Upload tar assets @@ -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/.github/workflows/v3_core_test.yml b/.github/workflows/v3_core_test.yml index 5035e812d..3628f578b 100644 --- a/.github/workflows/v3_core_test.yml +++ b/.github/workflows/v3_core_test.yml @@ -178,7 +178,7 @@ jobs: - name: Publish reports if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: jfoa-build-reports-${{ runner.os }} path: v3-core/mochawesome-report/ diff --git a/.github/workflows/web3_compatible.yml b/.github/workflows/web3_compatible.yml index 8e46c6cc9..860c6fce2 100644 --- a/.github/workflows/web3_compatible.yml +++ b/.github/workflows/web3_compatible.yml @@ -162,7 +162,7 @@ jobs: - name: Publish reports if: success() || failure() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: jfoa-build-reports-${{ runner.os }} path: axon-test/mochawesome-report/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c4caa24e..fa01f3aa6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ * fix!: fix the implementation of Axon Tries ([\#1580](https://github.com/axonweb3/axon/pull/1580)) * refactor!: call reserved system contract address is forbidden ([\#1597](https://github.com/axonweb3/axon/pull/1597)) * refactor!: change many U256 type to U64 ([\#1591](https://github.com/axonweb3/axon/pull/1591)) +* fix(mempool)!: check gas limit range ([\#1634](https://github.com/axonweb3/axon/pull/1634)) ### FEATURES @@ -18,7 +19,6 @@ * feat: add ckb mbt proof verify precompile contract ([\#1578](https://github.com/axonweb3/axon/pull/1578)) * feat: support stop at specific height ([\#1581](https://github.com/axonweb3/axon/pull/1581)) - ### BUG FIXES * Fix value of gas in JSON RPC Transaction should be gas limit ([\#1530](https://github.com/axonweb3/axon/pull/1530)) @@ -45,6 +45,7 @@ * refactor: rename Proof.block_hash serde to proposal_hash ([\#1618](https://github.com/axonweb3/axon/pull/1618)) * refactor: forbid call eth_getStorageAt to system contract accounts ([\#1619](https://github.com/axonweb3/axon/pull/1619)) * refactor: change estimate gas calculation logic ([\#1603](https://github.com/axonweb3/axon/pull/1603), [\#1626](https://github.com/axonweb3/axon/pull/1626)) +* refactor(cli): update keypair generate command ([\#1621](https://github.com/axonweb3/axon/pull/1621)) ### CHORE * ci: adjust CI after migrating the test projects ([\#1513](https://github.com/axonweb3/axon/pull/1513)) diff --git a/Cargo.lock b/Cargo.lock index 7a375eab7..8dc6989d3 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" @@ -366,6 +343,15 @@ dependencies = [ "tiny-keccak", ] +[[package]] +name = "axon-types" +version = "0.1.0" +source = "git+https://github.com/axonweb3/axon-contract.git?rev=b82a843#b82a843b36a5565524a14a537a5dbe393e26ca65" +dependencies = [ + "molecule", + "molecule2", +] + [[package]] name = "axum" version = "0.6.18" @@ -872,6 +858,7 @@ dependencies = [ "js-sys", "num-integer", "num-traits", + "serde", "time 0.1.45", "wasm-bindgen", "winapi", @@ -1392,22 +1379,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 +1391,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 +1415,7 @@ dependencies = [ "anstream", "anstyle", "clap_lex 0.5.0", - "strsim 0.10.0", + "strsim", ] [[package]] @@ -1815,9 +1786,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 +1798,7 @@ dependencies = [ "serde", "serde_json", "tempfile", + "tentacle-secio", "thiserror", ] @@ -2284,8 +2258,18 @@ version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.13.4", + "darling_macro 0.13.4", +] + +[[package]] +name = "darling" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +dependencies = [ + "darling_core 0.20.3", + "darling_macro 0.20.3", ] [[package]] @@ -2298,21 +2282,46 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim 0.10.0", + "strsim", "syn 1.0.109", ] +[[package]] +name = "darling_core" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.39", +] + [[package]] name = "darling_macro" version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ - "darling_core", + "darling_core 0.13.4", "quote", "syn 1.0.109", ] +[[package]] +name = "darling_macro" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +dependencies = [ + "darling_core 0.20.3", + "quote", + "syn 2.0.39", +] + [[package]] name = "dashmap" version = "5.5.3" @@ -2749,7 +2758,7 @@ name = "eth2_ssz_derive" version = "0.3.1" source = "git+https://github.com/synapseweb3/lighthouse?rev=be911e6#be911e6bd3f54ae84b01310b411be19e2b274634" dependencies = [ - "darling", + "darling 0.13.4", "proc-macro2", "quote", "syn 1.0.109", @@ -4054,6 +4063,7 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", + "serde", ] [[package]] @@ -4064,6 +4074,7 @@ checksum = "ad227c3af19d4914570ad36d30409928b75967c298feb9ea1969db3a610bb14e" dependencies = [ "equivalent", "hashbrown 0.14.0", + "serde", ] [[package]] @@ -4546,6 +4557,21 @@ dependencies = [ "safe_arith", ] +[[package]] +name = "metadata-cli" +version = "0.1.0" +dependencies = [ + "anyhow", + "axon-types", + "clap 4.4.6", + "hex", + "molecule", + "serde", + "serde_json", + "serde_with 3.4.0", + "toml 0.8.2", +] + [[package]] name = "metastruct" version = "0.1.1" @@ -4561,7 +4587,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37cb4045d5677b7da537f8cb5d0730d5b6414e3cc81c61e4b50e1f0cbdc73909" dependencies = [ - "darling", + "darling 0.13.4", "itertools", "proc-macro2", "quote", @@ -4632,6 +4658,11 @@ dependencies = [ "faster-hex 0.6.1", ] +[[package]] +name = "molecule2" +version = "0.1.0" +source = "git+https://github.com/axonweb3/axon-contract.git?rev=b82a843#b82a843b36a5565524a14a537a5dbe393e26ca65" + [[package]] name = "multimap" version = "0.8.3" @@ -6503,9 +6534,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -6549,7 +6580,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" dependencies = [ "serde", - "serde_with_macros", + "serde_with_macros 1.5.2", +] + +[[package]] +name = "serde_with" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23" +dependencies = [ + "base64 0.21.0", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.0.1", + "serde", + "serde_json", + "serde_with_macros 3.4.0", + "time 0.3.21", ] [[package]] @@ -6558,12 +6606,24 @@ version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" dependencies = [ - "darling", + "darling 0.13.4", "proc-macro2", "quote", "syn 1.0.109", ] +[[package]] +name = "serde_with_macros" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788" +dependencies = [ + "darling 0.20.3", + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "serde_yaml" version = "0.8.26" @@ -6573,7 +6633,7 @@ dependencies = [ "indexmap 1.9.3", "ryu", "serde", - "yaml-rust 0.4.5", + "yaml-rust", ] [[package]] @@ -6812,12 +6872,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" @@ -6871,7 +6925,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b9e5728aa1a87141cefd4e7509903fc01fa0dcb108022b1e841a67c5159fc5" dependencies = [ - "darling", + "darling 0.13.4", "itertools", "proc-macro2", "quote", @@ -7119,15 +7173,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" @@ -7232,8 +7277,10 @@ version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc" dependencies = [ + "itoa", "serde", "time-core", + "time-macros", ] [[package]] @@ -7242,6 +7289,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +[[package]] +name = "time-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +dependencies = [ + "time-core", +] + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -7582,7 +7638,7 @@ name = "tree_hash_derive" version = "0.4.0" source = "git+https://github.com/synapseweb3/lighthouse?rev=be911e6#be911e6bd3f54ae84b01310b411be19e2b274634" dependencies = [ - "darling", + "darling 0.13.4", "quote", "syn 1.0.109", ] @@ -7675,7 +7731,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "serde_with", + "serde_with 1.14.0", "serde_yaml", "slog", "smallvec", @@ -7809,12 +7865,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 +8259,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..d91998186 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ members = [ "core/storage", "devtools/abi-generator", "devtools/axon-tools", - "devtools/keypair", + "devtools/metadata-cli", "protocol", ] diff --git a/common/config-parser/src/types/spec.rs b/common/config-parser/src/types/spec.rs index 2b8971c94..1700aec46 100644 --- a/common/config-parser/src/types/spec.rs +++ b/common/config-parser/src/types/spec.rs @@ -12,7 +12,7 @@ use common_crypto::Secp256k1RecoverablePrivateKey; use protocol::{ codec::{decode_256bits_key, deserialize_address}, types::{ - HardforkInfoInner, Header, Key256Bits, Metadata, H160, H256, RLP_EMPTY_LIST, RLP_NULL, + HardforkInfoInner, Header, Key256Bits, SpecMetadata, H160, H256, RLP_EMPTY_LIST, RLP_NULL, U256, U64, }, }; @@ -30,7 +30,7 @@ pub struct ChainSpec { /// /// All parameters are not allowed to be modified after the chain /// initialized. - pub params: Metadata, + pub params: SpecMetadata, } #[derive(Clone, Debug, Deserialize)] 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/consensus/src/adapter.rs b/core/consensus/src/adapter.rs index 3cbd657bc..4b8715833 100644 --- a/core/consensus/src/adapter.rs +++ b/core/consensus/src/adapter.rs @@ -18,8 +18,8 @@ use protocol::traits::{ Network, PeerTrust, Priority, Rpc, Storage, SynchronizationAdapter, }; use protocol::types::{ - BatchSignedTxs, Block, BlockNumber, BlockVersion, Bytes, ExecResp, Hash, Header, Hex, - MerkleRoot, Metadata, PackedTxHashes, Proof, Proposal, Receipt, SignedTransaction, Validator, + BatchSignedTxs, Block, BlockNumber, BlockVersion, Bytes, ConsensusValidator, ExecResp, Hash, + Header, Hex, MerkleRoot, Metadata, PackedTxHashes, Proof, Proposal, Receipt, SignedTransaction, U256, }; use protocol::{async_trait, tokio::task, trie, ProtocolResult}; @@ -140,7 +140,7 @@ where prevote_ratio: u64, precommit_ratio: u64, brake_ratio: u64, - validators: Vec, + validators: Vec, ) -> ProtocolResult<()> { self.overlord_handler .read() diff --git a/core/consensus/src/consensus.rs b/core/consensus/src/consensus.rs index 714847fb7..b37dacbba 100644 --- a/core/consensus/src/consensus.rs +++ b/core/consensus/src/consensus.rs @@ -6,7 +6,7 @@ use overlord::types::{ use overlord::{DurationConfig, Overlord, OverlordHandler}; use protocol::traits::{Consensus, ConsensusAdapter, Context, NodeInfo}; -use protocol::types::{Proposal, Validator}; +use protocol::types::{ConsensusValidator, Proposal}; use protocol::{ async_trait, codec::ProtocolCodec, tokio::sync::Mutex as AsyncMutex, ProtocolResult, }; @@ -167,7 +167,7 @@ impl OverlordConsensus { &self, init_height: u64, interval: u64, - validators: Vec, + validators: Vec, timer_config: Option, ) -> ProtocolResult<()> { // The address field of Node struct should use the node's secp256k1 public key @@ -196,7 +196,7 @@ pub fn gen_overlord_status( prevote_ratio: u64, precommit_ratio: u64, brake_ratio: u64, - validators: Vec, + validators: Vec, ) -> Status { // The address field of Node struct should use the node's secp256k1 public key let mut authority_list = validators diff --git a/core/consensus/src/tests/mod.rs b/core/consensus/src/tests/mod.rs index f718ce35c..8e6af4301 100644 --- a/core/consensus/src/tests/mod.rs +++ b/core/consensus/src/tests/mod.rs @@ -11,10 +11,10 @@ use protocol::{ codec::hex_decode, traits::{CommonConsensusAdapter, Context, SynchronizationAdapter}, types::{ - Address, Block, BlockNumber, Bytes, Eip1559Transaction, ExecResp, Hash, Hasher, Header, - Hex, MerkleRoot, Metadata, Proof, Proposal, Public, Receipt, SignatureComponents, - SignedTransaction, TransactionAction, UnsignedTransaction, UnverifiedTransaction, - Validator, H160, H256, U256, U64, + Address, Block, BlockNumber, Bytes, ConsensusValidator, Eip1559Transaction, ExecResp, Hash, + Hasher, Header, Hex, MerkleRoot, Metadata, Proof, Proposal, Public, Receipt, + SignatureComponents, SignedTransaction, TransactionAction, UnsignedTransaction, + UnverifiedTransaction, H160, H256, U256, U64, }, ProtocolResult, }; @@ -93,12 +93,12 @@ fn _mock_pub_key() -> Hex { Hex::from_str("0x026c184a9016f6f71a234c86b141621f38b68c78602ab06768db4d83682c616004").unwrap() } -fn _mock_validators(len: usize) -> Vec { +fn _mock_validators(len: usize) -> Vec { (0..len).map(|_| _mock_validator()).collect::>() } -fn _mock_validator() -> Validator { - Validator { +fn _mock_validator() -> ConsensusValidator { + ConsensusValidator { pub_key: _mock_pub_key().as_bytes(), propose_weight: random::(), vote_weight: random::(), @@ -145,7 +145,7 @@ impl SynchronizationAdapter for MockSyncAdapter { prevote_ratio: u64, precommit_ratio: u64, brake_ratio: u64, - validators: Vec, + validators: Vec, ) -> ProtocolResult<()> { Ok(()) } diff --git a/core/executor/src/precompiles/call_ckb_vm.rs b/core/executor/src/precompiles/call_ckb_vm.rs index eb5f2469a..3574b9065 100644 --- a/core/executor/src/precompiles/call_ckb_vm.rs +++ b/core/executor/src/precompiles/call_ckb_vm.rs @@ -55,11 +55,11 @@ impl PrecompileContract for CallCkbVM { fn parse_input(input: &[u8]) -> Result<(CellDep, Vec), PrecompileFailure> { let payload = - ::decode(input).map_err(|_| err!(_, "decode input"))?; + <(CallCkbVmPayload,) as AbiDecode>::decode(input).map_err(|_| err!(_, "decode input"))?; Ok(( - payload.cell, - payload.inputs.into_iter().map(|i| i.0).collect(), + payload.0.cell, + payload.0.inputs.into_iter().map(|i| i.0).collect(), )) } diff --git a/core/executor/src/precompiles/ckb_mbt_verify.rs b/core/executor/src/precompiles/ckb_mbt_verify.rs index 349a6d64f..5b9c95bf5 100644 --- a/core/executor/src/precompiles/ckb_mbt_verify.rs +++ b/core/executor/src/precompiles/ckb_mbt_verify.rs @@ -67,7 +67,9 @@ impl PrecompileContract for CMBTVerify { } fn parse_input(input: &[u8]) -> Result { - ::decode(input).map_err(|_| err!(_, "decode input")) + <(VerifyProofPayload,) as AbiDecode>::decode(input) + .map(|r| r.0) + .map_err(|_| err!(_, "decode input")) } fn inner_verify_proof(payload: VerifyProofPayload) -> Result<(), PrecompileFailure> { diff --git a/core/executor/src/precompiles/get_cell.rs b/core/executor/src/precompiles/get_cell.rs index a1d65fe47..6f95e1ccf 100644 --- a/core/executor/src/precompiles/get_cell.rs +++ b/core/executor/src/precompiles/get_cell.rs @@ -52,7 +52,7 @@ impl PrecompileContract for GetCell { Ok(( PrecompileOutput { exit_status: ExitSucceed::Returned, - output: cell_opt.unwrap().encode(), + output: AbiEncode::encode((cell_opt.unwrap(),)), }, gas, )) diff --git a/core/executor/src/precompiles/get_header.rs b/core/executor/src/precompiles/get_header.rs index bca27de2b..dec2de745 100644 --- a/core/executor/src/precompiles/get_header.rs +++ b/core/executor/src/precompiles/get_header.rs @@ -1,10 +1,11 @@ -use ethers::abi::AbiDecode; +use ethers::abi::{AbiDecode, AbiEncode}; use evm::executor::stack::{PrecompileFailure, PrecompileOutput}; use evm::{Context, ExitError, ExitSucceed}; use protocol::types::{H160, H256}; use crate::precompiles::{axon_precompile_address, PrecompileContract}; +use crate::system_contract::ckb_light_client::ckb_light_client_abi; use crate::{err, system_contract::ckb_light_client::CkbHeaderReader, CURRENT_HEADER_CELL_ROOT}; #[derive(Default, Clone)] @@ -39,10 +40,13 @@ impl PrecompileContract for GetHeader { return err!("get header return None"); } + let header = + ::decode(header_opt.unwrap()).unwrap(); + Ok(( PrecompileOutput { exit_status: ExitSucceed::Returned, - output: header_opt.unwrap(), + output: AbiEncode::encode((header,)), }, gas, )) diff --git a/core/executor/src/precompiles/tests.rs b/core/executor/src/precompiles/tests.rs index f40f45777..89833bb51 100644 --- a/core/executor/src/precompiles/tests.rs +++ b/core/executor/src/precompiles/tests.rs @@ -303,11 +303,11 @@ fn test_verify_cmbt_proof() { proof: witness_proof, }; - let input = AbiEncode::encode(raw_tx_payload); + let input = AbiEncode::encode((raw_tx_payload,)); let output = vec![1u8]; test_precompile!(CMBTVerify, &input, output, 56000); - let input = AbiEncode::encode(witness_payload); + let input = AbiEncode::encode((witness_payload,)); let output = vec![1u8]; test_precompile!(CMBTVerify, &input, output, 56000); } 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..0c5763ef2 100644 --- a/core/run/src/lib.rs +++ b/core/run/src/lib.rs @@ -14,8 +14,8 @@ use protocol::traits::{ Context, Executor, Gossip, MemPool, Network, NodeInfo, PeerTrust, ReadOnlyStorage, Rpc, Storage, }; use protocol::types::{ - Block, Bloom, BloomInput, ExecResp, HardforkInfoInner, Header, Metadata, Proposal, RichBlock, - SignedTransaction, Validator, ValidatorExtend, H256, + Block, Bloom, BloomInput, ConsensusValidator, ExecResp, HardforkInfoInner, Header, Metadata, + Proposal, RichBlock, SignedTransaction, ValidatorExtend, H256, }; use protocol::{lazy::CHAIN_ID, trie::DB as TrieDB, ProtocolResult}; @@ -213,7 +213,8 @@ async fn start( metadata_handle.init_hardfork(current_block.header.number)?; let metadata = metadata_handle.get_metadata_by_block_number(current_block.header.number)?; - let validators: Vec = metadata.verifier_list.iter().map(Into::into).collect(); + let validators: Vec = + metadata.verifier_list.iter().map(Into::into).collect(); // Set args in mempool mempool.set_args( @@ -345,7 +346,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, @@ -417,7 +417,7 @@ async fn get_status_agent( fn run_overlord_consensus( metadata: Metadata, - validators: Vec, + validators: Vec, current_block: Block, overlord_consensus: Arc>>, ) where @@ -466,7 +466,7 @@ async fn execute_genesis( &partial_genesis, db_group, &spec.accounts, - &[metadata_0, metadata_1], + &[metadata_0.into(), metadata_1.into()], spec.genesis.generate_hardfork_info(), )?; diff --git a/core/run/src/tests.rs b/core/run/src/tests.rs index 693764308..3e0afd663 100644 --- a/core/run/src/tests.rs +++ b/core/run/src/tests.rs @@ -193,8 +193,8 @@ fn check_state(spec: &ChainSpec, genesis_header: &Header, db_group: &DatabaseGro ) .unwrap(); - let metadata_0 = spec.params.clone(); - let metadata_1 = { + let metadata_0: Metadata = spec.params.clone().into(); + let metadata_1: Metadata = { let mut tmp = metadata_0.clone(); tmp.epoch = metadata_0.epoch + 1; tmp.version.start = metadata_0.version.end + 1; diff --git a/devtools/axon-tools/src/precompile.rs b/devtools/axon-tools/src/precompile.rs index 56f5e447b..ccfe4ca65 100644 --- a/devtools/axon-tools/src/precompile.rs +++ b/devtools/axon-tools/src/precompile.rs @@ -1,6 +1,7 @@ use ckb_types::utilities::{merkle_root, MerkleProof}; use ckb_types::{packed, prelude::*}; use ethers_contract::{EthAbiCodec, EthAbiType}; +use rlp::{Encodable, RlpStream}; #[derive(EthAbiCodec, EthAbiType, Clone, Debug, PartialEq, Eq)] pub struct VerifyProofPayload { @@ -13,6 +14,17 @@ pub struct VerifyProofPayload { pub proof: Proof, } +impl Encodable for VerifyProofPayload { + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(5); + s.append(&self.verify_type); + s.append(&self.transactions_root.as_slice()); + s.append(&self.witnesses_root.as_slice()); + s.append(&self.raw_transactions_root.as_slice()); + s.append(&self.proof); + } +} + #[derive(EthAbiCodec, EthAbiType, Clone, Debug, PartialEq, Eq)] pub struct Proof { pub indices: Vec, @@ -20,6 +32,24 @@ pub struct Proof { pub leaves: Vec<[u8; 32]>, } +impl Encodable for Proof { + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(3); + s.append_list(&self.indices); + + // Append each lemma as a separate item + s.begin_list(self.lemmas.len()); + for lemma in &self.lemmas { + s.append(&lemma.as_slice()); + } + + // Append each leaf as a separate item + s.begin_list(self.leaves.len()); + for leaf in &self.leaves { + s.append(&leaf.as_slice()); + } + } +} /// A standalone function to verify the ckb-merkle-binary-tree proof. pub fn verify_proof(payload: VerifyProofPayload) -> Result<(), String> { // Firstly, verify the transactions_root is consist of the raw_transactions_root diff --git a/devtools/chain/specs/multi_nodes/chain-spec.toml b/devtools/chain/specs/multi_nodes/chain-spec.toml index 583fe7c05..34913943c 100644 --- a/devtools/chain/specs/multi_nodes/chain-spec.toml +++ b/devtools/chain/specs/multi_nodes/chain-spec.toml @@ -79,27 +79,23 @@ interval = 3000 [[params.verifier_list]] bls_pub_key = "0xa26e3fe1cf51bd4822072c61bdc315ac32e3d3c2e2484bb92942666399e863b4bf56cf2926383cc706ffc15dfebc85c6" pub_key = "0x031ddc35212b7fc7ff6685b17d91f77c972535aee5c7ae5684d3e72b986f08834b" -address = "0x8ab0cf264df99d83525e9e11c7e4db01558ae1b1" propose_weight = 1 vote_weight = 1 [[params.verifier_list]] bls_pub_key = "0x80310fa9df724b5603d283b472ed3bf85254a8a4ceda8a274b421f6cf2be1d9184267cdfe9a199d36ff14e57668a55d0" pub_key = "0x02b77c74eb68af3d4d6cc7884ed6709f1a2a1af0f713382a4438ec2ea3a70d4d7f" -address = "0xf386573563c3a75dbbd269fce9782620826ddac2" propose_weight = 1 vote_weight = 1 [[params.verifier_list]] bls_pub_key = "0x897721e9016864141a8b982a48217f66ef318ce598aa31842cddaaebe3cd7feab17050022afa6c2123aba39938fe4142" pub_key = "0x027ffd6a6a231561f2afe5878b1c743323b34263d16787130b1815fe35649b0bf5" -address = "0x8af204ac5d7cb8815a6c53a50b72d01e729d3b22" propose_weight = 1 vote_weight = 1 [[params.verifier_list]] bls_pub_key = "0x98eef09a3927acb225191101a1d9aa85775fdcdc87b9ba36898f6c132b485d66aef91c0f51cda331be4f985c3be6761c" pub_key = "0x0232c489c23b1207107e9a24648c1e4754a8c1c0b38db96df57a526201035058cb" -address = "0xf4cc1652dcec2e5de9ce6fb1b6f9fa9456e957f1" propose_weight = 1 vote_weight = 1 diff --git a/devtools/chain/specs/multi_nodes_short_epoch_len/chain-spec.toml b/devtools/chain/specs/multi_nodes_short_epoch_len/chain-spec.toml index 82c0784e9..f40e2d2d3 100644 --- a/devtools/chain/specs/multi_nodes_short_epoch_len/chain-spec.toml +++ b/devtools/chain/specs/multi_nodes_short_epoch_len/chain-spec.toml @@ -79,27 +79,23 @@ interval = 3000 [[params.verifier_list]] bls_pub_key = "0xa26e3fe1cf51bd4822072c61bdc315ac32e3d3c2e2484bb92942666399e863b4bf56cf2926383cc706ffc15dfebc85c6" pub_key = "0x031ddc35212b7fc7ff6685b17d91f77c972535aee5c7ae5684d3e72b986f08834b" -address = "0x8ab0cf264df99d83525e9e11c7e4db01558ae1b1" propose_weight = 1 vote_weight = 1 [[params.verifier_list]] bls_pub_key = "0x80310fa9df724b5603d283b472ed3bf85254a8a4ceda8a274b421f6cf2be1d9184267cdfe9a199d36ff14e57668a55d0" pub_key = "0x02b77c74eb68af3d4d6cc7884ed6709f1a2a1af0f713382a4438ec2ea3a70d4d7f" -address = "0xf386573563c3a75dbbd269fce9782620826ddac2" propose_weight = 1 vote_weight = 1 [[params.verifier_list]] bls_pub_key = "0x897721e9016864141a8b982a48217f66ef318ce598aa31842cddaaebe3cd7feab17050022afa6c2123aba39938fe4142" pub_key = "0x027ffd6a6a231561f2afe5878b1c743323b34263d16787130b1815fe35649b0bf5" -address = "0x8af204ac5d7cb8815a6c53a50b72d01e729d3b22" propose_weight = 1 vote_weight = 1 [[params.verifier_list]] bls_pub_key = "0x98eef09a3927acb225191101a1d9aa85775fdcdc87b9ba36898f6c132b485d66aef91c0f51cda331be4f985c3be6761c" pub_key = "0x0232c489c23b1207107e9a24648c1e4754a8c1c0b38db96df57a526201035058cb" -address = "0xf4cc1652dcec2e5de9ce6fb1b6f9fa9456e957f1" propose_weight = 1 vote_weight = 1 diff --git a/devtools/chain/specs/single_node/chain-spec.toml b/devtools/chain/specs/single_node/chain-spec.toml index 69b52ea4f..1dd4ad635 100644 --- a/devtools/chain/specs/single_node/chain-spec.toml +++ b/devtools/chain/specs/single_node/chain-spec.toml @@ -79,6 +79,5 @@ interval = 3000 [[params.verifier_list]] bls_pub_key = "0xa26e3fe1cf51bd4822072c61bdc315ac32e3d3c2e2484bb92942666399e863b4bf56cf2926383cc706ffc15dfebc85c6" pub_key = "0x031ddc35212b7fc7ff6685b17d91f77c972535aee5c7ae5684d3e72b986f08834b" -address = "0x8ab0cf264df99d83525e9e11c7e4db01558ae1b1" propose_weight = 1 vote_weight = 1 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 -} diff --git a/devtools/metadata-cli/Cargo.toml b/devtools/metadata-cli/Cargo.toml new file mode 100644 index 000000000..b04a5a0b0 --- /dev/null +++ b/devtools/metadata-cli/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "metadata-cli" +version = "0.1.0" +edition = "2021" +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[[bin]] +name = "axon-metadata" +path = "src/main.rs" + +[dependencies] +anyhow = "1.0.75" +axon-types = { git = "https://github.com/axonweb3/axon-contract.git", rev = "b82a843" } +clap = { version = "4.4.6", features = ["derive"] } +hex = "0.4.3" +molecule = "0.7.5" +serde = { version = "1.0.193", features = ["derive"] } +serde_json = "1.0.108" +serde_with = "3.4.0" +toml = "0.8.2" diff --git a/devtools/metadata-cli/README.md b/devtools/metadata-cli/README.md new file mode 100644 index 000000000..9a07a6e56 --- /dev/null +++ b/devtools/metadata-cli/README.md @@ -0,0 +1,25 @@ +# Metadata Cli + +Cli for working with axon metadata cell. + +## Get Data + +Generate `MetadataCellData` from validators. + +Usage: + +From a chain spec file or input file: + +```command +$ axon-metadata get-data -i input.example.toml +``` + +```command +$ axon-metadata get-data -i chain-spec.toml +``` + +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 +``` diff --git a/devtools/metadata-cli/input.example.json b/devtools/metadata-cli/input.example.json new file mode 100644 index 000000000..a9af6c241 --- /dev/null +++ b/devtools/metadata-cli/input.example.json @@ -0,0 +1,66 @@ +{ + "version": { + "start": "0x1", + "end": "0x5f5e100" + }, + "epoch": "0x0", + "verifier_list": [ + { + "bls_pub_key": "0x95a16ed1f4c43a7470917771bf820741dbd040c51967122de66dc5bc9f6eff5953a36be6c0fdf8c202a26d6f2b0f8885", + "pub_key": "0x035e184329714d7e3f7e39e5d96ac3be4835897adbaab85bae2558473391fa8fcf", + "address": "0x81fb11017e520fda13df35d1fd1a3903e384020f", + "propose_weight": "0x1", + "vote_weight": "0x1" + }, + { + "bls_pub_key": "0xa8d1c7c4152ce4ad8eff7ee90406b6cdf27eee97f0e520b8098a88ff3873c83aa8b74d9aab3a1c15361b5d3bc9224e9a", + "pub_key": "0x02f0018382fef706e37faf9770c14a58d35a457c7a2fa0ec84240d50b6d74f4adb", + "address": "0x7249d82017b77a5006808fe020e779af0d95e12e", + "propose_weight": "0x1", + "vote_weight": "0x1" + }, + { + "bls_pub_key": "0x8d999a5c29604f32950bfedf289f6b8e7e2f1a19f86b208d370024e709f77d1208f5e000dc4232a63064530613aa4b26", + "pub_key": "0x03ea501a5600c260b62ff0cdb0c227e9374643395243f026f9c73fe9aa8ebcfebd", + "address": "0x387f3253e85c320b5e881656447eedccf5230f22", + "propose_weight": "0x1", + "vote_weight": "0x1" + }, + { + "bls_pub_key": "0xafefcad3f6289c0bc0a9fd0015f533dcfcc1d7ba5161ff518702fee7aec33374a08d4fa45baeef85836c1e604e8f221d", + "pub_key": "0x02b2daf6d950f25735f2faa129cfe2a65c70bcbd4a050c9d18a06ed0e63a91f2a9", + "address": "0xc384b679bbc0de6e471fdb7735c0ff2d9508ece0", + "propose_weight": "0x1", + "vote_weight": "0x1" + } + ], + "propose_counter": [ + { + "address": "0x387f3253e85c320b5e881656447eedccf5230f22", + "count": "0xe605" + }, + { + "address": "0x7249d82017b77a5006808fe020e779af0d95e12e", + "count": "0xe605" + }, + { + "address": "0x81fb11017e520fda13df35d1fd1a3903e384020f", + "count": "0xe5f3" + }, + { + "address": "0xc384b679bbc0de6e471fdb7735c0ff2d9508ece0", + "count": "0xe5ff" + } + ], + "consensus_config": { + "gas_limit": "0x3e7fffffc18", + "interval": "0xbb8", + "propose_ratio": "0xf", + "prevote_ratio": "0xa", + "precommit_ratio": "0xa", + "brake_ratio": "0xa", + "tx_num_limit": "0x4e20", + "max_tx_size": "0x186a0000", + "max_contract_limit": "0xc000" + } +} diff --git a/devtools/metadata-cli/input.example.toml b/devtools/metadata-cli/input.example.toml new file mode 100644 index 000000000..004c87f65 --- /dev/null +++ b/devtools/metadata-cli/input.example.toml @@ -0,0 +1,24 @@ +[[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" + +[[verifier_list]] +bls_pub_key = "0x98eef09a3927acb225191101a1d9aa85775fdcdc87b9ba36898f6c132b485d66aef91c0f51cda331be4f985c3be6761c" +pub_key = "0x0232c489c23b1207107e9a24648c1e4754a8c1c0b38db96df57a526201035058cb" diff --git a/devtools/metadata-cli/src/main.rs b/devtools/metadata-cli/src/main.rs new file mode 100644 index 000000000..e13bac304 --- /dev/null +++ b/devtools/metadata-cli/src/main.rs @@ -0,0 +1,190 @@ +use std::path::PathBuf; + +use anyhow::{Context, Result}; +use axon_types::{ + basic::{Byte33, Byte48, Identity, Uint32, Uint64}, + metadata::{Metadata, MetadataCellData, MetadataList, ValidatorList}, +}; +use clap::{Parser, Subcommand}; +use molecule::prelude::{Builder, Entity}; +use serde::{Deserialize, Serialize}; +use serde_with::{serde_as, PickFirst}; + +mod serde_helpers; +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], + + #[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, + + #[serde_as(deserialize_as = "PickFirst<(_, HexU32)>")] + #[serde(default)] + pub propose_weight: u32, + + #[serde_as(deserialize_as = "PickFirst<(_, HexU32)>")] + #[serde(default)] + pub vote_weight: u32, +} + +impl From for axon_types::metadata::Validator { + fn from(value: Validator) -> Self { + 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()) + .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()) + .build() + } +} + +pub fn metadata_cell_data_with_validators(vs: ValidatorList) -> MetadataCellData { + MetadataCellData::new_builder() + .metadata( + MetadataList::new_builder() + .push(Metadata::new_builder().validators(vs).build()) + .build(), + ) + .build() +} + +#[derive(Deserialize, Serialize)] +pub struct Input { + #[serde(alias = "verifier_list")] + pub validators: Vec, +} + +#[derive(Deserialize, Serialize)] +pub struct Spec { + params: Input, +} + +#[derive(Parser)] +struct Cli { + #[clap(subcommand)] + command: Command, +} + +#[derive(Subcommand)] +enum Command { + GetData(GetData), +} + +impl Command { + fn run(self) -> Result<()> { + match self { + Command::GetData(g) => g.run(), + } + } +} + +#[derive(Parser)] +struct GetData { + #[arg(short, long)] + input: PathBuf, + #[arg(short, long)] + output: Option, + #[arg(long)] + binary: bool, +} + +impl GetData { + 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 = if input.trim_start().starts_with('{') { + serde_json::from_str(&input).context("parsing input")? + } else { + let spec_or_input: toml::Value = toml::from_str(&input).context("parsing input")?; + if spec_or_input.get("params").is_some_and(|v| v.is_table()) { + toml::from_str::(&input) + .context("parsing input")? + .params + } else { + toml::from_str::(&input).context("parsing input")? + } + }; + let mut vs = ValidatorList::new_builder(); + for v in input.validators { + vs = vs.push(v.into()); + } + let md = metadata_cell_data_with_validators(vs.build()); + if self.binary { + output.write_all(md.as_slice()).context("writing output")?; + } else { + writeln!(output, "0x{}", hex::encode(md.as_slice())).context("writing output")?; + } + Ok(()) + } +} + +fn main() -> Result<()> { + Cli::parse().command.run() +} + +#[cfg(test)] +mod tests { + use anyhow::{Context, Result}; + use clap::Parser; + + use super::GetData; + + #[test] + fn test_get_data() -> Result<()> { + GetData::parse_from([ + "get-data", + "-i", + concat!(env!("CARGO_MANIFEST_DIR"), "/input.example.toml",), + ]) + .run() + .context("test toml")?; + + GetData::parse_from([ + "get-data", + "-i", + concat!(env!("CARGO_MANIFEST_DIR"), "/input.example.json",), + ]) + .run() + .context("test json")?; + + GetData::parse_from([ + "get-data", + "-i", + concat!( + env!("CARGO_MANIFEST_DIR"), + "/../chain/specs/multi_nodes/chain-spec.toml", + ), + ]) + .run() + .context("test spec")?; + + Ok(()) + } +} diff --git a/devtools/metadata-cli/src/serde_helpers.rs b/devtools/metadata-cli/src/serde_helpers.rs new file mode 100644 index 000000000..fc4f732f3 --- /dev/null +++ b/devtools/metadata-cli/src/serde_helpers.rs @@ -0,0 +1,71 @@ +use serde::{de::Error, Deserialize}; +use serde_with::{DeserializeAs, SerializeAs}; + +pub struct HexBytes; + +impl SerializeAs for HexBytes +where + T: AsRef<[u8]>, +{ + fn serialize_as(source: &T, serializer: S) -> Result + where + S: serde::Serializer, + { + let source = source.as_ref(); + let mut ret = vec![0; 2 + source.len() * 2]; + ret[..2].copy_from_slice(b"0x"); + hex::encode_to_slice(source, &mut ret[2..]).map_err(serde::ser::Error::custom)?; + + serializer.serialize_str(unsafe { std::str::from_utf8_unchecked(&ret) }) + } +} + +impl<'de, T> DeserializeAs<'de, T> for HexBytes +where + T: TryFrom>, +{ + fn deserialize_as(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + hex::decode(s.strip_prefix("0x").unwrap_or(&s)) + .map_err(Error::custom)? + .try_into() + .map_err(|_e| { + Error::custom("failed to convert from vector, incorrect length?".to_string()) + }) + } +} + +pub struct HexU32; + +impl<'de> DeserializeAs<'de, u32> for HexU32 { + fn deserialize_as(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + let s = s + .strip_prefix("0x") + .ok_or_else(|| Error::custom("expect string that starts with `0x`"))?; + let v = u32::from_str_radix(s, 16).map_err(Error::custom)?; + Ok(v) + } +} + +pub struct HexU64; + +impl<'de> DeserializeAs<'de, u64> for HexU64 { + fn deserialize_as(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + let s = s + .strip_prefix("0x") + .ok_or_else(|| Error::custom("expect string that starts with `0x`"))?; + let v = u64::from_str_radix(s, 16).map_err(Error::custom)?; + Ok(v) + } +} diff --git a/protocol/src/traits/consensus.rs b/protocol/src/traits/consensus.rs index 688e88260..278343462 100644 --- a/protocol/src/traits/consensus.rs +++ b/protocol/src/traits/consensus.rs @@ -6,8 +6,9 @@ use std::{ use common_crypto::Secp256k1PublicKey; use crate::types::{ - Address, Block, BlockNumber, Bytes, ExecResp, HardforkInfoInner, Hash, Header, Hex, MerkleRoot, - Metadata, PackedTxHashes, Proof, Proposal, Receipt, SignedTransaction, Validator, U256, + Address, Block, BlockNumber, Bytes, ConsensusValidator, ExecResp, HardforkInfoInner, Hash, + Header, Hex, MerkleRoot, Metadata, PackedTxHashes, Proof, Proposal, Receipt, SignedTransaction, + U256, }; use crate::{async_trait, traits::Context, ProtocolResult}; @@ -72,7 +73,7 @@ pub trait SynchronizationAdapter: CommonConsensusAdapter + Send + Sync { prevote_ratio: u64, precommit_ratio: u64, brake_ratio: u64, - validators: Vec, + validators: Vec, ) -> ProtocolResult<()>; /// Pull some blocks from other nodes from `begin` to `end`. diff --git a/protocol/src/types/primitive.rs b/protocol/src/types/primitive.rs index e2b47e5b4..c2847a206 100644 --- a/protocol/src/types/primitive.rs +++ b/protocol/src/types/primitive.rs @@ -308,6 +308,19 @@ impl MetadataVersion { } } +#[derive( + RlpEncodable, RlpDecodable, Serialize, Deserialize, Default, Clone, Debug, PartialEq, Eq, +)] +pub struct SpecMetadata { + pub version: MetadataVersion, + #[cfg_attr(feature = "hex-serialize", serde(serialize_with = "serialize_uint"))] + pub epoch: u64, + pub verifier_list: Vec, + #[serde(skip_deserializing)] + pub propose_counter: Vec, + pub consensus_config: ConsensusConfig, +} + #[derive( RlpEncodable, RlpDecodable, Serialize, Deserialize, Default, Clone, Debug, PartialEq, Eq, )] @@ -321,6 +334,18 @@ pub struct Metadata { pub consensus_config: ConsensusConfig, } +impl From for Metadata { + fn from(value: SpecMetadata) -> Self { + Metadata { + version: value.version, + epoch: value.epoch, + verifier_list: value.verifier_list.into_iter().map(Into::into).collect(), + propose_counter: value.propose_counter, + consensus_config: value.consensus_config, + } + } +} + impl Metadata { pub fn into_part(self) -> (MetadataInner, ConsensusConfig) { ( @@ -468,12 +493,33 @@ impl From<(H160, u64)> for ProposeCount { } #[derive(RlpEncodable, RlpDecodable, Clone, Debug, PartialEq, Eq)] -pub struct Validator { +pub struct ConsensusValidator { pub pub_key: Bytes, pub propose_weight: u32, pub vote_weight: u32, } +#[derive( + RlpEncodable, RlpDecodable, Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Display, +)] +#[display( + fmt = "Validator {{ \ + bls_pub_key: {}, pub_key: {}, propose_weight: {}, vote_weight: {} \ + }}", + bls_pub_key, + pub_key, + propose_weight, + vote_weight +)] +pub struct Validator { + pub bls_pub_key: Hex, + pub pub_key: Hex, + #[cfg_attr(feature = "hex-serialize", serde(serialize_with = "serialize_uint"))] + pub propose_weight: u32, + #[cfg_attr(feature = "hex-serialize", serde(serialize_with = "serialize_uint"))] + pub vote_weight: u32, +} + #[derive(RlpEncodable, RlpDecodable, Serialize, Deserialize, Clone, PartialEq, Eq, Display)] #[display( fmt = "ValidatorExtend {{ \ @@ -495,6 +541,20 @@ pub struct ValidatorExtend { pub vote_weight: u32, } +impl From for ValidatorExtend { + fn from(value: Validator) -> Self { + let address = + Address::from_pubkey_bytes(value.pub_key.as_ref()).expect("invalid public key"); + ValidatorExtend { + bls_pub_key: value.bls_pub_key, + address: address.0, + pub_key: value.pub_key, + propose_weight: value.propose_weight, + vote_weight: value.vote_weight, + } + } +} + impl PartialOrd for ValidatorExtend { fn partial_cmp(&self, other: &Self) -> Option { Some(self.bls_pub_key.cmp(&other.bls_pub_key)) @@ -507,9 +567,9 @@ impl Ord for ValidatorExtend { } } -impl From<&ValidatorExtend> for Validator { +impl From<&ValidatorExtend> for ConsensusValidator { fn from(ve: &ValidatorExtend) -> Self { - Validator { + ConsensusValidator { pub_key: ve.pub_key.as_bytes(), propose_weight: ve.propose_weight, vote_weight: ve.vote_weight,