├── .dockerignore
├── .github
├── dependabot.yml
├── issue_template.md
├── pull_request_template.md
└── workflows
│ ├── ansible
│ └── update_edgenet.yaml
│ ├── build.yml
│ ├── ci.yml
│ ├── cla.yml
│ ├── deploy.devnet.eph.yml
│ ├── deploy.devnet.yml
│ ├── deploy.testnet.yml
│ ├── deploy_edgenet.yaml
│ ├── e2e.yaml
│ ├── lint.yml
│ ├── pandoras_box.yml
│ ├── release.yml
│ ├── security.yml
│ └── test.yml
├── .gitignore
├── .gitmodules
├── .golangci.yml
├── .goreleaser.yml
├── CLA.md
├── Dockerfile.release
├── LICENSE
├── Makefile
├── README.md
├── SECURITY.md
├── ValidatorGuide.md
├── archive
├── backup.go
├── backup_test.go
├── restore.go
├── restore_test.go
└── types.go
├── blockchain
├── blockchain.go
├── blockchain_test.go
├── storage
│ ├── keyvalue.go
│ ├── leveldb
│ │ ├── leveldb.go
│ │ └── leveldb_test.go
│ ├── memory
│ │ ├── memory.go
│ │ └── memory_test.go
│ ├── storage.go
│ ├── testing.go
│ └── utils.go
├── subscription.go
├── subscription_test.go
└── testing.go
├── chain
├── chain.go
├── chain_test.go
├── params.go
└── params_test.go
├── codecov.yml
├── command
├── backup
│ ├── backup.go
│ ├── params.go
│ └── result.go
├── cli_output.go
├── common.go
├── common_output.go
├── default.go
├── genesis
│ ├── genesis.go
│ ├── params.go
│ ├── predeploy
│ │ ├── genesis_predeploy.go
│ │ ├── params.go
│ │ └── result.go
│ ├── result.go
│ └── utils.go
├── helper
│ └── helper.go
├── ibft
│ ├── candidates
│ │ ├── ibft_candidates.go
│ │ └── result.go
│ ├── helper
│ │ └── vote.go
│ ├── ibft.go
│ ├── propose
│ │ ├── ibft_propose.go
│ │ ├── params.go
│ │ └── result.go
│ ├── quorum
│ │ ├── ibft_quorum.go
│ │ ├── params.go
│ │ └── result.go
│ ├── snapshot
│ │ ├── ibft_snapshot.go
│ │ ├── params.go
│ │ └── result.go
│ ├── status
│ │ ├── ibft_status.go
│ │ └── result.go
│ └── switch
│ │ ├── ibft_switch.go
│ │ ├── params.go
│ │ └── result.go
├── json_output.go
├── license
│ ├── license.go
│ └── result.go
├── monitor
│ ├── monitor.go
│ └── result.go
├── output.go
├── peers
│ ├── add
│ │ ├── params.go
│ │ ├── peers_add.go
│ │ └── result.go
│ ├── list
│ │ ├── peers_list.go
│ │ └── result.go
│ ├── peers.go
│ └── status
│ │ ├── params.go
│ │ ├── peers_status.go
│ │ └── result.go
├── root
│ └── root.go
├── secrets
│ ├── generate
│ │ ├── params.go
│ │ ├── result.go
│ │ └── secrets_generate.go
│ ├── init
│ │ ├── params.go
│ │ ├── result.go
│ │ └── secrets_init.go
│ ├── output
│ │ ├── params.go
│ │ ├── result.go
│ │ └── secrets_output.go
│ └── secrets.go
├── server
│ ├── config
│ │ └── config.go
│ ├── export
│ │ ├── export.go
│ │ ├── params.go
│ │ └── result.go
│ ├── init.go
│ ├── params.go
│ └── server.go
├── status
│ ├── result.go
│ └── status.go
├── txpool
│ ├── status
│ │ ├── result.go
│ │ └── txpool_status.go
│ ├── subscribe
│ │ ├── params.go
│ │ ├── result.go
│ │ └── txpool_subscribe.go
│ └── txpool.go
├── version
│ ├── result.go
│ └── version.go
└── whitelist
│ ├── deployment
│ ├── deployment.go
│ ├── params.go
│ └── result.go
│ ├── show
│ ├── params.go
│ ├── result.go
│ └── show.go
│ └── whitelist.go
├── consensus
├── consensus.go
├── dev
│ └── dev.go
├── dummy
│ └── dummy.go
├── ibft
│ ├── consensus.go
│ ├── consensus_backend.go
│ ├── consensus_backend_test.go
│ ├── fork
│ │ ├── fork.go
│ │ ├── fork_test.go
│ │ ├── helper.go
│ │ ├── helper_test.go
│ │ ├── hookregister.go
│ │ ├── hooks.go
│ │ ├── hooks_test.go
│ │ ├── manager.go
│ │ ├── manager_test.go
│ │ ├── storewrapper.go
│ │ ├── storewrapper_test.go
│ │ ├── type.go
│ │ └── type_test.go
│ ├── helper_test.go
│ ├── hook
│ │ ├── hook.go
│ │ └── hook_test.go
│ ├── ibft.go
│ ├── messages.go
│ ├── operator_service.go
│ ├── proto
│ │ ├── ibft_operator.pb.go
│ │ ├── ibft_operator.proto
│ │ └── ibft_operator_grpc.pb.go
│ ├── sign_test.go
│ ├── signer
│ │ ├── bls.go
│ │ ├── bls_test.go
│ │ ├── ecdsa.go
│ │ ├── ecdsa_test.go
│ │ ├── extra.go
│ │ ├── extra_test.go
│ │ ├── helper.go
│ │ ├── helper_test.go
│ │ ├── key_manager.go
│ │ ├── mock_test.go
│ │ ├── signer.go
│ │ └── signer_test.go
│ ├── state_test.go
│ ├── transport.go
│ ├── validators.go
│ └── verifier.go
└── utils.go
├── contracts
├── abis
│ ├── abis.go
│ └── json.go
└── staking
│ ├── query.go
│ └── query_test.go
├── crypto
├── crypto.go
├── crypto_test.go
├── txsigner.go
└── txsigner_test.go
├── docker
└── local
│ ├── Dockerfile
│ ├── docker-compose.yml
│ └── exzocoin.sh
├── e2e
├── README.md
├── broadcast_test.go
├── const.go
├── discovery_test.go
├── framework
│ ├── config.go
│ ├── helper.go
│ ├── ibft.go
│ └── testserver.go
├── genesis_test.go
├── ibft_test.go
├── jsonrpc_test.go
├── logs_test.go
├── metadata
│ ├── StressTest.sol
│ ├── predeploy.sol
│ ├── predeploy_abi.json
│ └── sample.sol
├── pos_poa_switch_test.go
├── pos_test.go
├── syncer_test.go
├── transaction_test.go
├── txpool_test.go
└── websocket_test.go
├── generate_dependency_licenses.sh
├── go.mod
├── go.sum
├── helper
├── common
│ └── common.go
├── config
│ └── config.go
├── enode
│ ├── enode.go
│ └── enode_test.go
├── hex
│ ├── hex.go
│ └── hex_test.go
├── ipc
│ ├── ipc_unix.go
│ └── ipc_windows.go
├── keccak
│ ├── keccak.go
│ ├── keccak_test.go
│ └── pool.go
├── keystore
│ └── keystore.go
├── predeployment
│ ├── argparser.go
│ ├── argparser_test.go
│ └── predeployment.go
├── progress
│ └── chain.go
├── staking
│ └── staking.go
└── tests
│ ├── assert.go
│ └── testing.go
├── jsonrpc
├── codec.go
├── codec_test.go
├── debug_endpoint.go
├── debug_endpoint_test.go
├── dispatcher.go
├── dispatcher_test.go
├── errors.go
├── eth_blockchain_test.go
├── eth_endpoint.go
├── eth_endpoint_test.go
├── eth_state_test.go
├── eth_txpool_test.go
├── filter_manager.go
├── filter_manager_test.go
├── helper.go
├── helper_test.go
├── jsonrpc.go
├── jsonrpc_test.go
├── mocks_test.go
├── net_endpoint.go
├── net_endpoint_test.go
├── query.go
├── query_test.go
├── testsuite
│ ├── block-empty.json
│ ├── block-with-txn-bodies.json
│ ├── block-with-txn-hashes.json
│ ├── transaction-pending.json
│ └── transaction-sealed.json
├── txpool_endpoint.go
├── txpool_endpoint_test.go
├── types.go
├── types_test.go
├── web3_endpoint.go
└── web3_endpoint_test.go
├── licenses
├── bsd_licenses.json
└── licenses.go
├── main.go
├── mainnet-genesis.json
├── network
├── bootnodes.go
├── common
│ └── common.go
├── config.go
├── connections.go
├── dial
│ ├── dial_queue.go
│ ├── dial_queue_test.go
│ ├── dial_task.go
│ └── heap.go
├── discovery
│ ├── discovery.go
│ └── discovery_test.go
├── discovery_e2e_test.go
├── e2e_testing.go
├── event
│ └── peer_event.go
├── gossip.go
├── gossip_test.go
├── grpc
│ └── grpc.go
├── identity
│ ├── identity.go
│ └── identity_test.go
├── identity_e2e_test.go
├── keystore.go
├── proto
│ ├── discovery.pb.go
│ ├── discovery.proto
│ ├── discovery_grpc.pb.go
│ ├── identity.pb.go
│ ├── identity.proto
│ ├── identity_grpc.pb.go
│ ├── testing.pb.go
│ ├── testing.proto
│ └── testing_grpc.pb.go
├── server.go
├── server_discovery.go
├── server_identity.go
├── server_test.go
└── testing
│ └── testing.go
├── secrets
├── awsssm
│ └── aws_ssm.go
├── config.go
├── gcpssm
│ └── gcp_ssm.go
├── hashicorpvault
│ └── hashicorp_vault.go
├── helper
│ └── helper.go
├── local
│ ├── local.go
│ └── local_test.go
├── secrets.go
└── secrets_test.go
├── server
├── builtin.go
├── config.go
├── proto
│ ├── system.pb.go
│ ├── system.proto
│ └── system_grpc.pb.go
├── server.go
├── server_metrics.go
└── system_service.go
├── state
├── executor.go
├── immutable-trie
│ ├── encoding.go
│ ├── encoding_test.go
│ ├── hasher.go
│ ├── snapshot.go
│ ├── state.go
│ ├── state_test.go
│ ├── storage.go
│ └── trie.go
├── runtime
│ ├── evm
│ │ ├── bitmap.go
│ │ ├── bitmap_test.go
│ │ ├── dispatch_table.go
│ │ ├── dispatch_table_test.go
│ │ ├── evm.go
│ │ ├── evm_test.go
│ │ ├── instructions.go
│ │ ├── instructions_test.go
│ │ ├── opcodes.go
│ │ ├── opcodes_test.go
│ │ ├── state.go
│ │ └── state_test.go
│ ├── precompiled
│ │ ├── base.go
│ │ ├── base_test.go
│ │ ├── blake2f.go
│ │ ├── blake2f_test.go
│ │ ├── bn256.go
│ │ ├── bn256_test.go
│ │ ├── fixtures
│ │ │ └── blake2f.json
│ │ ├── modexp.go
│ │ ├── modexp_test.go
│ │ ├── precompiled.go
│ │ └── testing.go
│ ├── runtime.go
│ └── tracer
│ │ ├── structtracer
│ │ ├── tracer.go
│ │ └── tracer_test.go
│ │ └── types.go
├── state.go
├── testing.go
├── transition_test.go
├── txn.go
└── txn_test.go
├── syncer
├── client.go
├── client_test.go
├── peers.go
├── peers_test.go
├── proto
│ ├── syncer.pb.go
│ ├── syncer.proto
│ └── syncer_grpc.pb.go
├── service.go
├── service_test.go
├── syncer.go
├── syncer_test.go
└── types.go
├── testnet-genesis.json
├── tests
├── evm_test.go
├── state_test.go
└── testing.go
├── txpool
├── account.go
├── event_manager.go
├── event_manager_test.go
├── event_queue.go
├── event_subscription.go
├── event_subscription_test.go
├── lookup_map.go
├── mock_test.go
├── operator.go
├── proto
│ ├── operator.pb.go
│ ├── operator.proto
│ ├── operator_grpc.pb.go
│ ├── v1.pb.go
│ └── v1.proto
├── query.go
├── queue.go
├── slot_gauge.go
├── txpool.go
└── txpool_test.go
├── types
├── buildroot
│ ├── buildroot.go
│ ├── buildroot_fast.go
│ └── buildroot_fast_test.go
├── encoding.go
├── header.go
├── header_hash.go
├── receipt.go
├── rlp_encoding_test.go
├── rlp_marshal.go
├── rlp_marshal_storage.go
├── rlp_unmarshal.go
├── rlp_unmarshal_storage.go
├── transaction.go
├── types.go
└── types_test.go
├── validators
├── bls.go
├── bls_test.go
├── ecdsa.go
├── ecdsa_test.go
├── helper.go
├── helper_test.go
├── json_test.go
├── set.go
├── set_test.go
├── store
│ ├── contract
│ │ ├── contract.go
│ │ ├── contract_test.go
│ │ ├── fetcher.go
│ │ └── fetcher_test.go
│ ├── snapshot
│ │ ├── helper.go
│ │ ├── helper_test.go
│ │ ├── snapshot.go
│ │ ├── snapshot_test.go
│ │ ├── types.go
│ │ └── types_test.go
│ ├── test_helper.go
│ ├── types.go
│ └── types_test.go
├── types.go
└── types_test.go
└── versioning
└── versioning.go
/.dockerignore:
--------------------------------------------------------------------------------
1 | docker/local/Dockerfile
2 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: gomod
4 | directory: /
5 | target-branch: "develop"
6 | schedule:
7 | interval: weekly
8 | ignore:
9 | - dependency-name: "github.com/aws/aws-sdk-go"
10 | update-types: [ "version-update:semver-patch" ]
11 | open-pull-requests-limit: 10
12 | pull-request-branch-name:
13 | separator: "-"
14 | reviewers:
15 | - "lazartravica"
16 | - "Kourin1996"
17 | - "zivkovicmilos"
18 |
--------------------------------------------------------------------------------
/.github/issue_template.md:
--------------------------------------------------------------------------------
1 | # [ Subject of the issue ]
2 | ## Description
3 | Describe your issue in as much detail as possible here.
4 |
5 | ## Your environment
6 | - OS and version.
7 | - The version of the Polygon Edge.
8 | (*Confirm the version of your Polygon edge client by running the following command: `exzocoin version --grpc-address GRPC_ADDRESS`*)
9 | - The branch that causes this issue.
10 | - Locally or Cloud hosted (which provider).
11 | - Please confirm if the validators are running under containerized environment (K8s, Docker, etc.).
12 |
13 | ## Steps to reproduce
14 | - Tell us how to reproduce this issue.
15 | - Where the issue is, if you know.
16 | - Which commands triggered the issue, if any.
17 | - Provide us with the content of your genesis file.
18 | - Provide us with commands that you used to start your validators.
19 | - Provide us with the peer list of each of your validators by running the following command: `exzocoin peers list --grpc-address GRPC_ADDRESS`.
20 | - Is the chain producing blocks and serving customers atm?
21 |
22 | ## Expected behavior
23 | - Tell us what should happen.
24 | - Tell us what happened instead.
25 |
26 | ## Logs
27 | Provide us with debug logs from all of your validators by setting logging to `debug` output with: `server --log-level debug`
28 |
29 | ## Proposed solution
30 | If you have an idea on how to fix this issue, please write it down here, so we can begin discussing it
31 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # Description
2 |
3 | Please provide a detailed description of what was done in this PR
4 |
5 | # Changes include
6 |
7 | - [ ] Bugfix (non-breaking change that solves an issue)
8 | - [ ] Hotfix (change that solves an urgent issue, and requires immediate attention)
9 | - [ ] New feature (non-breaking change that adds functionality)
10 | - [ ] Breaking change (change that is not backwards-compatible and/or changes current functionality)
11 |
12 | # Breaking changes
13 |
14 | Please complete this section if any breaking changes have been made, otherwise delete it
15 |
16 | # Checklist
17 |
18 | - [ ] I have assigned this PR to myself
19 | - [ ] I have added at least 1 reviewer
20 | - [ ] I have added the relevant labels
21 | - [ ] I have updated the official documentation
22 | - [ ] I have added sufficient documentation in code
23 |
24 | ## Testing
25 |
26 | - [ ] I have tested this code with the official test suite
27 | - [ ] I have tested this code manually
28 |
29 | ### Manual tests
30 |
31 | Please complete this section if you ran manual tests for this functionality, otherwise delete it
32 |
33 | # Documentation update
34 |
35 | Please link the documentation update PR in this section if it's present, otherwise delete it
36 |
37 | # Additional comments
38 |
39 | Please post additional comments in this section if you have them, otherwise delete it
40 |
--------------------------------------------------------------------------------
/.github/workflows/ansible/update_edgenet.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | -
3 | name: Update Polygon Edge binary
4 | hosts:
5 | - all
6 | become: yes
7 | tasks:
8 | ## update & upgrade system
9 | - name: Update & upgrade system
10 | apt:
11 | upgrade: yes
12 | update_cache: yes
13 |
14 | ## stop exzocoin service
15 | - name: Stop polygon edge service
16 | systemd:
17 | state: stopped
18 | name: exzocoin
19 |
20 | ## get the latest release
21 | - name: Get latest release link
22 | uri:
23 | url: https://api.github.com/repos/ExzoNetwork/ExzoCoin/releases/latest
24 | return_content: true
25 | register: edge_release
26 |
27 | ## download the latest release
28 | - name: Download latest Polygon Edge release
29 | get_url:
30 | url: "{{ edge_release.json.assets[3].browser_download_url }}"
31 | dest: /tmp/exzocoin.tar.gz
32 | force: yes
33 |
34 | ## create temp dir for release
35 | - name: Create temp dir for Polygon Edge release
36 | file:
37 | path: /tmp/exzocoin
38 | state: directory
39 |
40 | ## unpack release tar
41 | - name: Unpack Polygon Edge release
42 | unarchive:
43 | remote_src: yes
44 | src: /tmp/exzocoin.tar.gz
45 | dest: /tmp/exzocoin
46 |
47 | ## set exzocoin to PATH
48 | - name: Place Polygon Edge binary to PATH
49 | copy:
50 | remote_src: yes
51 | src: /tmp/exzocoin/exzocoin
52 | dest: /usr/local/bin/
53 | mode: a+x
54 | force: yes
55 |
56 | ## remove release temp dir
57 | - name: Remove temp Polygon Edge release dir
58 | file:
59 | state: absent
60 | path: /tmp/exzocoin
61 |
62 | ## start polygon edge service
63 | - name: Start exzocoin service
64 | systemd:
65 | state: restarted
66 | name: exzocoin
67 | daemon_reload: yes
68 | enabled: yes
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: Build
3 | on: # yamllint disable-line rule:truthy
4 | workflow_dispatch:
5 | workflow_call:
6 |
7 | jobs:
8 | go_build:
9 | name: Polygon Edge
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Checkout code
13 | uses: actions/checkout@v3
14 | - name: Setup Go environment
15 | uses: actions/setup-go@v3.3.0
16 | with:
17 | go-version: 1.18.x
18 |
19 | - name: Build Polygon Edge
20 | run: go build -tags netgo -ldflags="-s -w -linkmode external -extldflags "-static" -X \"github.com/ExzoNetwork/ExzoCoin/versioning.Version=${GITHUB_REF_NAME}\" -X \"github.com/ExzoNetwork/ExzoCoin/versioning.Commit=${GITHUB_SHA}\"" && tar -czvf exzocoin.tar.gz exzocoin
21 | env:
22 | CC: gcc
23 | CXX: g++
24 | GOARC: amd64
25 | GOOS: linux
26 |
27 | - name: 'Upload Artifact'
28 | uses: actions/upload-artifact@v3
29 | with:
30 | name: exzocoin
31 | path: exzocoin.tar.gz
32 | retention-days: 3
33 |
34 | go_build_reproducibility:
35 | name: Verify Build Reproducibility
36 | runs-on: ubuntu-latest
37 | continue-on-error: true
38 | steps:
39 | - name: Checkout code
40 | uses: actions/checkout@v3
41 | - name: Setup Go environment
42 | uses: actions/setup-go@v3.3.0
43 | with:
44 | go-version: 1.18.x
45 |
46 | - name: 'Reproduce builds'
47 | continue-on-error: true
48 | run: |
49 | go build -o ./edge-1 -trimpath -buildvcs=false
50 | go build -o ./edge-2 -trimpath -buildvcs=false
51 |
52 | buildsha1=$(shasum -a256 ./edge-1 | awk '{print $1}')
53 | buildsha2=$(shasum -a256 ./edge-2 | awk '{print $1}')
54 |
55 | echo "Build 1 SHA: $buildsha1"
56 | echo "Build 2 SHA: $buildsha2"
57 |
58 | if [ "$buildsha1" != "$buildsha2" ]; then
59 | echo "Build artifact does not match original"
60 | exit 1
61 | else
62 | echo "Build artifact matches original"
63 | fi
64 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: Pull Request CI
3 | on: # yamllint disable-line rule:truthy
4 | workflow_dispatch: {}
5 | pull_request:
6 |
7 | jobs:
8 | build:
9 | name: Build
10 | uses: ./.github/workflows/build.yml
11 |
12 | test:
13 | name: Test
14 | uses: ./.github/workflows/test.yml
15 | needs: build
16 |
--------------------------------------------------------------------------------
/.github/workflows/cla.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: "CLA Assistant"
3 | on: # yamllint disable-line rule:truthy
4 | issue_comment:
5 | types:
6 | - created
7 | pull_request_target:
8 | types:
9 | - opened
10 | - closed
11 | - synchronize
12 |
13 | jobs:
14 | CLAssistant:
15 | runs-on: ubuntu-latest
16 | steps:
17 | - name: "CLA Assistant"
18 | if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
19 | # Beta Release
20 | uses: cla-assistant/github-action@v2.1.3-beta
21 | env:
22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
23 | # the below token should have repo scope and must be manually added by you in the repository's secret
24 | PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
25 | with:
26 | path-to-signatures: 'cla.json'
27 | path-to-document: 'https://github.com/ExzoNetwork/ExzoCoin/blob/develop/CLA.md'
28 | branch: 'cla-signatures'
29 | allowlist: dependabot[bot],dependabot-preview[bot]
30 |
--------------------------------------------------------------------------------
/.github/workflows/deploy_edgenet.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | on: # yamllint disable-line rule:truthy
3 | release:
4 | types:
5 | - published
6 |
7 | jobs:
8 | deploy_to_edge_net:
9 | name: Update EdgeNet
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Get aws-commander
13 | run: |
14 | wget https://github.com/Trapesys/aws-commander/releases/download/v0.2.0/aws-commander_0.2.0_Linux_x86_64.tar.gz
15 | tar -xf aws-commander_0.2.0_Linux_x86_64.tar.gz
16 | sudo mv aws-commander /usr/local/bin
17 |
18 | - name: Checkout code
19 | uses: actions/checkout@v3
20 |
21 | - name: Run deployment Ansible
22 | env:
23 | AWS_ACCESS_KEY_ID: ${{ secrets.EDGENET_AWS_ACCESS_KEY_ID }}
24 | AWS_SECRET_ACCESS_KEY: ${{ secrets.EDGENET_AWS_SECRET_ACCESS_KEY }}
25 | run: >
26 | /usr/local/bin/aws-commander
27 | -instances i-039f7c0b3328a00f8,i-035b9f2d78cfb8ea9,i-00a6c7cb3a213f21f,i-03ac2f42ddcba6120
28 | -mode ansible
29 | -playbook .github/workflows/ansible/update_edgenet.yaml
30 | -aws-zone us-west-2
31 |
--------------------------------------------------------------------------------
/.github/workflows/e2e.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | name: E2E tests
3 | on: # yamllint disable-line rule:truthy
4 | push:
5 | branches:
6 | - main
7 | - develop
8 | pull_request:
9 |
10 | jobs:
11 | build:
12 | runs-on: ubuntu-latest
13 | env:
14 | E2E_TESTS: true
15 | E2E_LOGS: true
16 | CI_VERBOSE: true
17 | steps:
18 | - uses: actions/checkout@v2
19 | - name: Install Go
20 | uses: actions/setup-go@v3
21 | with:
22 | go-version: 1.18.x
23 | - name: Run tests
24 | run: make test-e2e
25 | - name: Archive test logs
26 | if: always()
27 | uses: actions/upload-artifact@v3
28 | with:
29 | name: e2e-logs
30 | path: e2e-logs-*/
31 | retention-days: 30
32 |
--------------------------------------------------------------------------------
/.github/workflows/lint.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: Lint
3 | on: # yamllint disable-line rule:truthy
4 | push:
5 | branches-ignore:
6 | - 'develop'
7 | - 'release/**'
8 | tags-ignore:
9 | - 'v*'
10 | paths:
11 | - '**.go'
12 | workflow_call: {}
13 | workflow_dispatch: {}
14 |
15 | jobs:
16 | golangci_lint:
17 | runs-on: ubuntu-latest
18 | steps:
19 | - name: Install Go
20 | uses: actions/setup-go@v3
21 | with:
22 | go-version: 1.18.x
23 |
24 | - name: Checkout code
25 | uses: actions/checkout@v3
26 |
27 | - name: Lint
28 | uses: golangci/golangci-lint-action@v3
29 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: Release
3 | on: # yamllint disable-line rule:truthy
4 | push:
5 | branches-ignore:
6 | - '**'
7 | tags:
8 | - 'v*.*.*'
9 | # to be used by fork patch-releases ^^
10 | - 'v*.*.*-*'
11 |
12 | jobs:
13 | goreleaser:
14 | runs-on: ubuntu-latest
15 | steps:
16 | - name: Checkout
17 | uses: actions/checkout@v2
18 | with:
19 | fetch-depth: 0
20 |
21 | - name: Set up Go
22 | uses: actions/setup-go@master
23 | with:
24 | go-version: 1.18.x
25 |
26 | - name: Prepare
27 | id: prepare
28 | run: |
29 | TAG=${GITHUB_REF#refs/tags/}
30 | echo ::set-output name=tag_name::${TAG}
31 | - name: Set up QEMU
32 | uses: docker/setup-qemu-action@v1
33 |
34 | - name: Run GoReleaser
35 | run: |
36 | docker run \
37 | --rm \
38 | --privileged \
39 | -e CGO_ENABLED=1 \
40 | -e GITHUB_TOKEN \
41 | -e DOCKER_USERNAME \
42 | -e DOCKER_PASSWORD \
43 | -e SLACK_WEBHOOK \
44 | -v /var/run/docker.sock:/var/run/docker.sock \
45 | -v `pwd`:/go/src/$(PACKAGE_NAME) \
46 | -w /go/src/$(PACKAGE_NAME) \
47 | ghcr.io/goreleaser/goreleaser-cross:${GOLANG_CROSS_VERSION} \
48 | --rm-dist --skip-validate
49 | env:
50 | PACKAGE_NAME: github.com/ExzoNetwork/ExzoCoin
51 | GOLANG_CROSS_VERSION: v1.18.3
52 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
53 | VERSION: ${{ steps.prepare.outputs.tag_name }}
54 | SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
55 | SLACK_CHANNEL: ${{ secrets.SLACK_CHANNEL }}
56 | DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
57 | DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
58 |
--------------------------------------------------------------------------------
/.github/workflows/security.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: Security Scan
3 | on: # yamllint disable-line rule:truthy
4 | workflow_call:
5 | secrets:
6 | SNYK_TOKEN:
7 | required: true
8 | SNYK_ORG:
9 | required: true
10 | workflow_dispatch: {}
11 | schedule:
12 | - cron: '0 0 * * 0'
13 |
14 | jobs:
15 | snyk:
16 | name: Snyk and Publish
17 | runs-on: ubuntu-latest
18 | continue-on-error: true
19 | steps:
20 | - name: Checkout Source
21 | uses: actions/checkout@master
22 | - name: Run Snyk to check for vulnerabilities
23 | uses: snyk/actions/golang@master
24 | continue-on-error: true
25 | env:
26 | SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
27 | with:
28 | args: --org=${{ secrets.SNYK_ORG }} --sarif-file-output=snyk.sarif
29 | - name: Upload result to GitHub Code Scanning
30 | uses: github/codeql-action/upload-sarif@v2
31 | with:
32 | sarif_file: snyk.sarif
33 | snyk-code:
34 | name: Snyk Code and Publish
35 | runs-on: ubuntu-latest
36 | continue-on-error: true
37 | steps:
38 | - name: Checkout Source
39 | uses: actions/checkout@master
40 | - name: Run Snyk SAST to check for vulnerabilities
41 | uses: snyk/actions/golang@master
42 | continue-on-error: true
43 | env:
44 | SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
45 | with:
46 | args: --org=${{ secrets.SNYK_ORG }} --sarif-file-output=snyk.sarif
47 | command: code test
48 | - name: Upload result to GitHub Code Scanning
49 | uses: github/codeql-action/upload-sarif@v2
50 | with:
51 | sarif_file: snyk.sarif
52 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: Test
3 | on: # yamllint disable-line rule:truthy
4 | workflow_dispatch:
5 | workflow_call:
6 |
7 | jobs:
8 | go_test:
9 | name: Polygon Edge
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Setup Go
13 | uses: actions/setup-go@v3
14 | with:
15 | go-version: 1.18.x
16 |
17 | - name: Checkout Code
18 | uses: actions/checkout@v3
19 | with:
20 | submodules: recursive
21 |
22 | - name: Run Go Test
23 | run: go test -coverprofile coverage.out -timeout 20m `go list ./... | grep -v e2e`
24 |
25 | - name: Upload coverage file to Codecov
26 | uses: codecov/codecov-action@v3
27 | with:
28 | files: coverage.out
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | peers.json
2 | genesis.json
3 | secretsManagerConfig.json
4 | *-packr.go
5 | config*.json
6 |
7 | bin/
8 |
9 | test-chain*
10 | exzocoin-chain*
11 | .idea
12 |
13 | # Exclude the build .exe file from version control
14 | dist/
15 | main.exe
16 | main
17 |
18 | # MacOS Leftovers
19 | .DS_Store
20 | .vscode
21 |
22 | # exclude build folder
23 | artifacts
24 |
25 | # Log files
26 | *.log
27 |
28 | vendor/
29 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "tests/tests"]
2 | path = tests/tests
3 | url = https://github.com/ethereum/tests.git
4 |
--------------------------------------------------------------------------------
/Dockerfile.release:
--------------------------------------------------------------------------------
1 | FROM alpine:3.14
2 |
3 | RUN set -x \
4 | && apk add --update --no-cache \
5 | ca-certificates \
6 | && rm -rf /var/cache/apk/*
7 | COPY exzocoin /usr/local/bin/
8 |
9 | EXPOSE 8545 9632 1478
10 | ENTRYPOINT ["exzocoin"]
11 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 |
2 | .PHONY: download-spec-tests
3 | download-spec-tests:
4 | git submodule init
5 | git submodule update
6 |
7 | .PHONY: bindata
8 | bindata:
9 | go-bindata -pkg chain -o ./chain/chain_bindata.go ./chain/chains
10 |
11 | .PHONY: protoc
12 | protoc:
13 | protoc --go_out=. --go-grpc_out=. ./server/proto/*.proto
14 | protoc --go_out=. --go-grpc_out=. ./protocol/proto/*.proto
15 | protoc --go_out=. --go-grpc_out=. ./network/proto/*.proto
16 | protoc --go_out=. --go-grpc_out=. ./txpool/proto/*.proto
17 | protoc --go_out=. --go-grpc_out=. ./consensus/ibft/**/*.proto
18 |
19 | .PHONY: build
20 | build:
21 | $(eval LATEST_VERSION = $(shell git describe --tags --abbrev=0))
22 | $(eval COMMIT_HASH = $(shell git rev-parse HEAD))
23 | $(eval BRANCH = $(shell git rev-parse --abbrev-ref HEAD | tr -d '\040\011\012\015\n'))
24 | $(eval TIME = $(shell date))
25 | go build -o exzocoin -ldflags="\
26 | -X 'github.com/ExzoNetwork/ExzoCoin/versioning.Version=$(LATEST_VERSION)' \
27 | -X 'github.com/ExzoNetwork/ExzoCoin/versioning.Commit=$(COMMIT_HASH)'\
28 | -X 'github.com/ExzoNetwork/ExzoCoin/versioning.Branch=$(BRANCH)'\
29 | -X 'github.com/ExzoNetwork/ExzoCoin/versioning.BuildTime=$(TIME)'" \
30 | main.go
31 |
32 | .PHONY: lint
33 | lint:
34 | golangci-lint run --config .golangci.yml
35 |
36 | .PHONY: generate-bsd-licenses
37 | generate-bsd-licenses:
38 | ./generate_dependency_licenses.sh BSD-3-Clause,BSD-2-Clause > ./licenses/bsd_licenses.json
39 |
40 | .PHONY: test
41 | test:
42 | go test -timeout=20m `go list ./... | grep -v e2e`
43 |
44 | .PHONY: test-e2e
45 | test-e2e:
46 | # We need to build the binary with the race flag enabled
47 | # because it will get picked up and run during e2e tests
48 | # and the e2e tests should error out if any kind of race is found
49 | go build -race -o artifacts/exzocoin .
50 | env EDGE_BINARY=${PWD}/artifacts/exzocoin go test -v -timeout=30m ./e2e/...
51 |
52 | .PHONY: run-local
53 | run-local:
54 | docker-compose -f ./docker/local/docker-compose.yml up -d --build
55 |
56 | .PHONY: stop-local
57 | stop-local:
58 | docker-compose -f ./docker/local/docker-compose.yml stop
59 |
60 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Polygon Technology Security Information
2 |
3 | ## Link to vulnerability disclosure details (Bug Bounty).
4 | - Websites and Applications: https://hackerone.com/polygon-technology
5 | - Smart Contracts: https://immunefi.com/bounty/polygon
6 |
7 | ## Languages that our team speaks and understands.
8 | Preferred-Languages: en
9 |
10 | ## Security-related job openings at Polygon.
11 | https://polygon.technology/careers
12 |
13 | ## Polygon security contact details.
14 | security@polygon.technology
15 |
16 | ## The URL for accessing the security.txt file.
17 | Canonical: https://polygon.technology/security.txt
18 |
--------------------------------------------------------------------------------
/archive/types.go:
--------------------------------------------------------------------------------
1 | package archive
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/types"
7 | "github.com/umbracle/fastrlp"
8 | )
9 |
10 | // Metadata is the data stored in the beginning of backup
11 | type Metadata struct {
12 | Latest uint64
13 | LatestHash types.Hash
14 | }
15 |
16 | // MarshalRLP returns RLP encoded bytes
17 | func (m *Metadata) MarshalRLP() []byte {
18 | return m.MarshalRLPTo(nil)
19 | }
20 |
21 | // MarshalRLPTo sets RLP encoded bytes to given byte slice
22 | func (m *Metadata) MarshalRLPTo(dst []byte) []byte {
23 | return types.MarshalRLPTo(m.MarshalRLPWith, dst)
24 | }
25 |
26 | // MarshalRLPWith appends own field into arena for encode
27 | func (m *Metadata) MarshalRLPWith(arena *fastrlp.Arena) *fastrlp.Value {
28 | vv := arena.NewArray()
29 |
30 | vv.Set(arena.NewUint(m.Latest))
31 | vv.Set(arena.NewBytes(m.LatestHash.Bytes()))
32 |
33 | return vv
34 | }
35 |
36 | // UnmarshalRLP unmarshals and sets the fields from RLP encoded bytes
37 | func (m *Metadata) UnmarshalRLP(input []byte) error {
38 | return types.UnmarshalRlp(m.UnmarshalRLPFrom, input)
39 | }
40 |
41 | // UnmarshalRLPFrom sets the fields from parsed RLP encoded value
42 | func (m *Metadata) UnmarshalRLPFrom(p *fastrlp.Parser, v *fastrlp.Value) error {
43 | elems, err := v.GetElems()
44 | if err != nil {
45 | return err
46 | }
47 |
48 | if len(elems) < 2 {
49 | return fmt.Errorf("incorrect number of elements to decode Metadata, expected 2 but found %d", len(elems))
50 | }
51 |
52 | if m.Latest, err = elems[0].GetUint64(); err != nil {
53 | return err
54 | }
55 |
56 | if err = elems[1].GetHash(m.LatestHash[:]); err != nil {
57 | return err
58 | }
59 |
60 | return nil
61 | }
62 |
--------------------------------------------------------------------------------
/blockchain/storage/leveldb/leveldb.go:
--------------------------------------------------------------------------------
1 | package leveldb
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/blockchain/storage"
7 | "github.com/hashicorp/go-hclog"
8 | "github.com/syndtr/goleveldb/leveldb"
9 | )
10 |
11 | // Factory creates a leveldb storage
12 | func Factory(config map[string]interface{}, logger hclog.Logger) (storage.Storage, error) {
13 | path, ok := config["path"]
14 | if !ok {
15 | return nil, fmt.Errorf("path not found")
16 | }
17 |
18 | pathStr, ok := path.(string)
19 | if !ok {
20 | return nil, fmt.Errorf("path is not a string")
21 | }
22 |
23 | return NewLevelDBStorage(pathStr, logger)
24 | }
25 |
26 | // NewLevelDBStorage creates the new storage reference with leveldb
27 | func NewLevelDBStorage(path string, logger hclog.Logger) (storage.Storage, error) {
28 | db, err := leveldb.OpenFile(path, nil)
29 | if err != nil {
30 | return nil, err
31 | }
32 |
33 | kv := &levelDBKV{db}
34 |
35 | return storage.NewKeyValueStorage(logger.Named("leveldb"), kv), nil
36 | }
37 |
38 | // levelDBKV is the leveldb implementation of the kv storage
39 | type levelDBKV struct {
40 | db *leveldb.DB
41 | }
42 |
43 | // Set sets the key-value pair in leveldb storage
44 | func (l *levelDBKV) Set(p []byte, v []byte) error {
45 | return l.db.Put(p, v, nil)
46 | }
47 |
48 | // Get retrieves the key-value pair in leveldb storage
49 | func (l *levelDBKV) Get(p []byte) ([]byte, bool, error) {
50 | data, err := l.db.Get(p, nil)
51 | if err != nil {
52 | if err.Error() == "leveldb: not found" {
53 | return nil, false, nil
54 | }
55 |
56 | return nil, false, err
57 | }
58 |
59 | return data, true, nil
60 | }
61 |
62 | // Close closes the leveldb storage instance
63 | func (l *levelDBKV) Close() error {
64 | return l.db.Close()
65 | }
66 |
--------------------------------------------------------------------------------
/blockchain/storage/leveldb/leveldb_test.go:
--------------------------------------------------------------------------------
1 | package leveldb
2 |
3 | import (
4 | "os"
5 | "testing"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/blockchain/storage"
8 | "github.com/hashicorp/go-hclog"
9 | )
10 |
11 | func newStorage(t *testing.T) (storage.Storage, func()) {
12 | t.Helper()
13 |
14 | path, err := os.MkdirTemp("/tmp", "minimal_storage")
15 | if err != nil {
16 | t.Fatal(err)
17 | }
18 |
19 | s, err := NewLevelDBStorage(path, hclog.NewNullLogger())
20 | if err != nil {
21 | t.Fatal(err)
22 | }
23 |
24 | closeFn := func() {
25 | if err := s.Close(); err != nil {
26 | t.Fatal(err)
27 | }
28 |
29 | if err := os.RemoveAll(path); err != nil {
30 | t.Fatal(err)
31 | }
32 | }
33 |
34 | return s, closeFn
35 | }
36 |
37 | func TestStorage(t *testing.T) {
38 | storage.TestStorage(t, newStorage)
39 | }
40 |
--------------------------------------------------------------------------------
/blockchain/storage/memory/memory.go:
--------------------------------------------------------------------------------
1 | package memory
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/blockchain/storage"
5 | "github.com/ExzoNetwork/ExzoCoin/helper/hex"
6 | "github.com/hashicorp/go-hclog"
7 | )
8 |
9 | // NewMemoryStorage creates the new storage reference with inmemory
10 | func NewMemoryStorage(logger hclog.Logger) (storage.Storage, error) {
11 | db := &memoryKV{map[string][]byte{}}
12 |
13 | return storage.NewKeyValueStorage(logger, db), nil
14 | }
15 |
16 | // memoryKV is an in memory implementation of the kv storage
17 | type memoryKV struct {
18 | db map[string][]byte
19 | }
20 |
21 | func (m *memoryKV) Set(p []byte, v []byte) error {
22 | m.db[hex.EncodeToHex(p)] = v
23 |
24 | return nil
25 | }
26 |
27 | func (m *memoryKV) Get(p []byte) ([]byte, bool, error) {
28 | v, ok := m.db[hex.EncodeToHex(p)]
29 | if !ok {
30 | return nil, false, nil
31 | }
32 |
33 | return v, true, nil
34 | }
35 |
36 | func (m *memoryKV) Close() error {
37 | return nil
38 | }
39 |
--------------------------------------------------------------------------------
/blockchain/storage/memory/memory_test.go:
--------------------------------------------------------------------------------
1 | package memory
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/blockchain/storage"
7 | )
8 |
9 | func TestStorage(t *testing.T) {
10 | t.Helper()
11 |
12 | f := func(t *testing.T) (storage.Storage, func()) {
13 | t.Helper()
14 |
15 | s, _ := NewMemoryStorage(nil)
16 |
17 | return s, func() {}
18 | }
19 | storage.TestStorage(t, f)
20 | }
21 |
--------------------------------------------------------------------------------
/blockchain/storage/storage.go:
--------------------------------------------------------------------------------
1 | package storage
2 |
3 | import (
4 | "math/big"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/types"
7 | "github.com/hashicorp/go-hclog"
8 | )
9 |
10 | // Storage is a generic blockchain storage
11 | type Storage interface {
12 | ReadCanonicalHash(n uint64) (types.Hash, bool)
13 | WriteCanonicalHash(n uint64, hash types.Hash) error
14 |
15 | ReadHeadHash() (types.Hash, bool)
16 | ReadHeadNumber() (uint64, bool)
17 | WriteHeadHash(h types.Hash) error
18 | WriteHeadNumber(uint64) error
19 |
20 | WriteForks(forks []types.Hash) error
21 | ReadForks() ([]types.Hash, error)
22 |
23 | WriteTotalDifficulty(hash types.Hash, diff *big.Int) error
24 | ReadTotalDifficulty(hash types.Hash) (*big.Int, bool)
25 |
26 | WriteHeader(h *types.Header) error
27 | ReadHeader(hash types.Hash) (*types.Header, error)
28 |
29 | WriteCanonicalHeader(h *types.Header, diff *big.Int) error
30 |
31 | WriteBody(hash types.Hash, body *types.Body) error
32 | ReadBody(hash types.Hash) (*types.Body, error)
33 |
34 | WriteReceipts(hash types.Hash, receipts []*types.Receipt) error
35 | ReadReceipts(hash types.Hash) ([]*types.Receipt, error)
36 |
37 | WriteTxLookup(hash types.Hash, blockHash types.Hash) error
38 | ReadTxLookup(hash types.Hash) (types.Hash, bool)
39 |
40 | Close() error
41 | }
42 |
43 | // Factory is a factory method to create a blockchain storage
44 | type Factory func(config map[string]interface{}, logger hclog.Logger) (Storage, error)
45 |
--------------------------------------------------------------------------------
/blockchain/storage/utils.go:
--------------------------------------------------------------------------------
1 | package storage
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/types"
5 | "github.com/umbracle/fastrlp"
6 | )
7 |
8 | type Forks []types.Hash
9 |
10 | // MarshalRLPTo is a wrapper function for calling the type marshal implementation
11 | func (f *Forks) MarshalRLPTo(dst []byte) []byte {
12 | return types.MarshalRLPTo(f.MarshalRLPWith, dst)
13 | }
14 |
15 | // MarshalRLPWith is the actual RLP marshal implementation for the type
16 | func (f *Forks) MarshalRLPWith(ar *fastrlp.Arena) *fastrlp.Value {
17 | var vr *fastrlp.Value
18 |
19 | if len(*f) == 0 {
20 | vr = ar.NewNullArray()
21 | } else {
22 | vr = ar.NewArray()
23 |
24 | for _, fork := range *f {
25 | vr.Set(ar.NewCopyBytes(fork[:]))
26 | }
27 | }
28 |
29 | return vr
30 | }
31 |
32 | // UnmarshalRLP is a wrapper function for calling the type unmarshal implementation
33 | func (f *Forks) UnmarshalRLP(input []byte) error {
34 | return types.UnmarshalRlp(f.UnmarshalRLPFrom, input)
35 | }
36 |
37 | // UnmarshalRLPFrom is the actual RLP unmarshal implementation for the type
38 | func (f *Forks) UnmarshalRLPFrom(p *fastrlp.Parser, v *fastrlp.Value) error {
39 | elems, err := v.GetElems()
40 | if err != nil {
41 | return err
42 | }
43 |
44 | forks := make([]types.Hash, len(elems))
45 | for indx, elem := range elems {
46 | if err := elem.GetHash(forks[indx][:]); err != nil {
47 | return err
48 | }
49 | }
50 |
51 | *f = forks
52 |
53 | return nil
54 | }
55 |
--------------------------------------------------------------------------------
/blockchain/subscription_test.go:
--------------------------------------------------------------------------------
1 | package blockchain
2 |
3 | import (
4 | "sync"
5 | "testing"
6 | "time"
7 |
8 | "github.com/ExzoNetwork/ExzoCoin/types"
9 | "github.com/stretchr/testify/assert"
10 | )
11 |
12 | func TestSubscription(t *testing.T) {
13 | t.Parallel()
14 |
15 | var (
16 | e = &eventStream{}
17 | sub = e.subscribe()
18 | caughtEventNum = uint64(0)
19 | event = &Event{
20 | NewChain: []*types.Header{
21 | {
22 | Number: 100,
23 | },
24 | },
25 | }
26 |
27 | wg sync.WaitGroup
28 | )
29 |
30 | defer sub.Close()
31 |
32 | updateCh := sub.GetEventCh()
33 |
34 | wg.Add(1)
35 |
36 | go func() {
37 | defer wg.Done()
38 |
39 | select {
40 | case ev := <-updateCh:
41 | caughtEventNum = ev.NewChain[0].Number
42 | case <-time.After(5 * time.Second):
43 | }
44 | }()
45 |
46 | // Send the event to the channel
47 | e.push(event)
48 |
49 | // Wait for the event to be parsed
50 | wg.Wait()
51 |
52 | assert.Equal(t, event.NewChain[0].Number, caughtEventNum)
53 | }
54 |
--------------------------------------------------------------------------------
/chain/params_test.go:
--------------------------------------------------------------------------------
1 | package chain
2 |
3 | import (
4 | "encoding/json"
5 | "reflect"
6 | "testing"
7 | )
8 |
9 | func TestParamsForks(t *testing.T) {
10 | cases := []struct {
11 | input string
12 | output *Forks
13 | }{
14 | {
15 | input: `{
16 | "homestead": 1000
17 | }`,
18 | output: &Forks{
19 | Homestead: NewFork(1000),
20 | },
21 | },
22 | }
23 |
24 | for _, c := range cases {
25 | var dec *Forks
26 | if err := json.Unmarshal([]byte(c.input), &dec); err != nil {
27 | if c.output != nil {
28 | t.Fatal(err)
29 | }
30 | } else if !reflect.DeepEqual(dec, c.output) {
31 | t.Fatal("bad")
32 | }
33 | }
34 | }
35 |
36 | func TestParamsForksInTime(t *testing.T) {
37 | f := Forks{
38 | Homestead: NewFork(0),
39 | Byzantium: NewFork(1000),
40 | Constantinople: NewFork(1001),
41 | EIP150: NewFork(2000),
42 | }
43 |
44 | ff := f.At(1000)
45 |
46 | expect := func(name string, found bool, expect bool) {
47 | if expect != found {
48 | t.Fatalf("fork %s should be %v but found %v", name, expect, found)
49 | }
50 | }
51 |
52 | expect("homestead", ff.Homestead, true)
53 | expect("byzantium", ff.Byzantium, true)
54 | expect("constantinople", ff.Constantinople, false)
55 | expect("eip150", ff.EIP150, false)
56 | }
57 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | coverage:
2 | status:
3 | project:
4 | default:
5 | target: auto
6 | threshold: 0%
--------------------------------------------------------------------------------
/command/backup/backup.go:
--------------------------------------------------------------------------------
1 | package backup
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/command"
5 | "github.com/spf13/cobra"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | )
9 |
10 | func GetCommand() *cobra.Command {
11 | backupCmd := &cobra.Command{
12 | Use: "backup",
13 | Short: "Create blockchain backup file by fetching blockchain data from the running node",
14 | PreRunE: runPreRun,
15 | Run: runCommand,
16 | }
17 |
18 | helper.RegisterGRPCAddressFlag(backupCmd)
19 |
20 | setFlags(backupCmd)
21 | helper.SetRequiredFlags(backupCmd, params.getRequiredFlags())
22 |
23 | return backupCmd
24 | }
25 |
26 | func setFlags(cmd *cobra.Command) {
27 | cmd.Flags().StringVar(
28 | ¶ms.out,
29 | outFlag,
30 | "",
31 | "the export path for the backup",
32 | )
33 |
34 | cmd.Flags().StringVar(
35 | ¶ms.fromRaw,
36 | fromFlag,
37 | "0",
38 | "the beginning height of the chain in backup",
39 | )
40 |
41 | cmd.Flags().StringVar(
42 | ¶ms.toRaw,
43 | toFlag,
44 | "",
45 | "the end height of the chain in backup",
46 | )
47 | }
48 |
49 | func runPreRun(_ *cobra.Command, _ []string) error {
50 | return params.validateFlags()
51 | }
52 |
53 | func runCommand(cmd *cobra.Command, _ []string) {
54 | outputter := command.InitializeOutputter(cmd)
55 | defer outputter.WriteOutput()
56 |
57 | if err := params.createBackup(helper.GetGRPCAddress(cmd)); err != nil {
58 | outputter.SetError(err)
59 |
60 | return
61 | }
62 |
63 | outputter.SetCommandResult(params.getResult())
64 | }
65 |
--------------------------------------------------------------------------------
/command/backup/result.go:
--------------------------------------------------------------------------------
1 | package backup
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | )
9 |
10 | type BackupResult struct {
11 | From uint64 `json:"from"`
12 | To uint64 `json:"to"`
13 | Out string `json:"out"`
14 | }
15 |
16 | func (r *BackupResult) GetOutput() string {
17 | var buffer bytes.Buffer
18 |
19 | buffer.WriteString("\n[BACKUP]\n")
20 | buffer.WriteString("Exported backup file successfully:\n")
21 | buffer.WriteString(helper.FormatKV([]string{
22 | fmt.Sprintf("File|%s", r.Out),
23 | fmt.Sprintf("From|%d", r.From),
24 | fmt.Sprintf("To|%d", r.To),
25 | }))
26 |
27 | return buffer.String()
28 | }
29 |
--------------------------------------------------------------------------------
/command/cli_output.go:
--------------------------------------------------------------------------------
1 | package command
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | )
7 |
8 | type CLIOutput struct {
9 | commonOutputFormatter
10 | }
11 |
12 | func newCLIOutput() *CLIOutput {
13 | return &CLIOutput{}
14 | }
15 |
16 | func (cli *CLIOutput) WriteOutput() {
17 | if cli.errorOutput != nil {
18 | _, _ = fmt.Fprintln(os.Stderr, cli.getErrorOutput())
19 |
20 | return
21 | }
22 |
23 | _, _ = fmt.Fprintln(os.Stdout, cli.getCommandOutput())
24 | }
25 |
26 | func (cli *CLIOutput) getErrorOutput() string {
27 | return cli.errorOutput.Error()
28 | }
29 |
30 | func (cli *CLIOutput) getCommandOutput() string {
31 | return cli.commandOutput.GetOutput()
32 | }
33 |
--------------------------------------------------------------------------------
/command/common_output.go:
--------------------------------------------------------------------------------
1 | package command
2 |
3 | type commonOutputFormatter struct {
4 | errorOutput error
5 | commandOutput CommandResult
6 | }
7 |
8 | func (c *commonOutputFormatter) SetError(err error) {
9 | c.errorOutput = err
10 | }
11 |
12 | func (c *commonOutputFormatter) SetCommandResult(result CommandResult) {
13 | c.commandOutput = result
14 | }
15 |
--------------------------------------------------------------------------------
/command/default.go:
--------------------------------------------------------------------------------
1 | package command
2 |
3 | import "github.com/ExzoNetwork/ExzoCoin/server"
4 |
5 | const (
6 | DefaultGenesisFileName = "genesis.json"
7 | DefaultChainName = "exzocoin"
8 | DefaultChainID = 1229
9 | DefaultPremineBalance = "0xD3C21BCECCEDA1000000" // 1 million units of native network currency
10 | DefaultConsensus = server.IBFTConsensus
11 | DefaultGenesisGasUsed = 458752 // 0x70000
12 | DefaultGenesisGasLimit = 5242880 // 0x500000
13 | )
14 |
15 | const (
16 | JSONOutputFlag = "json"
17 | GRPCAddressFlag = "grpc-address"
18 | JSONRPCFlag = "jsonrpc"
19 | )
20 |
21 | // GRPCAddressFlagLEGACY Legacy flag that needs to be present to preserve backwards
22 | // compatibility with running clients
23 | const (
24 | GRPCAddressFlagLEGACY = "grpc"
25 | )
26 |
--------------------------------------------------------------------------------
/command/genesis/predeploy/genesis_predeploy.go:
--------------------------------------------------------------------------------
1 | package predeploy
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/command"
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | "github.com/spf13/cobra"
9 | )
10 |
11 | func GetCommand() *cobra.Command {
12 | genesisPredeployCmd := &cobra.Command{
13 | Use: "predeploy",
14 | Short: "Specifies the contract to be predeployed on chain start",
15 | PreRunE: runPreRun,
16 | Run: runCommand,
17 | }
18 |
19 | setFlags(genesisPredeployCmd)
20 | helper.SetRequiredFlags(genesisPredeployCmd, params.getRequiredFlags())
21 |
22 | return genesisPredeployCmd
23 | }
24 |
25 | func setFlags(cmd *cobra.Command) {
26 | cmd.Flags().StringVar(
27 | ¶ms.genesisPath,
28 | chainFlag,
29 | fmt.Sprintf("./%s", command.DefaultGenesisFileName),
30 | "the genesis file to update",
31 | )
32 |
33 | cmd.Flags().StringVar(
34 | ¶ms.addressRaw,
35 | predeployAddressFlag,
36 | predeployAddressMin.String(),
37 | fmt.Sprintf("the address to predeploy to. Must be >= %s", predeployAddressMin.String()),
38 | )
39 |
40 | cmd.Flags().StringVar(
41 | ¶ms.artifactsPath,
42 | artifactsPathFlag,
43 | "",
44 | "the path to the contract artifacts JSON",
45 | )
46 |
47 | cmd.Flags().StringArrayVar(
48 | ¶ms.constructorArgs,
49 | constructorArgsPath,
50 | []string{},
51 | "the constructor arguments, if any",
52 | )
53 | }
54 |
55 | func runPreRun(_ *cobra.Command, _ []string) error {
56 | return params.initRawParams()
57 | }
58 |
59 | func runCommand(cmd *cobra.Command, _ []string) {
60 | outputter := command.InitializeOutputter(cmd)
61 | defer outputter.WriteOutput()
62 |
63 | if err := params.updateGenesisConfig(); err != nil {
64 | outputter.SetError(err)
65 |
66 | return
67 | }
68 |
69 | if err := params.overrideGenesisConfig(); err != nil {
70 | outputter.SetError(err)
71 |
72 | return
73 | }
74 |
75 | outputter.SetCommandResult(params.getResult())
76 | }
77 |
--------------------------------------------------------------------------------
/command/genesis/predeploy/result.go:
--------------------------------------------------------------------------------
1 | package predeploy
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | )
9 |
10 | type GenesisPredeployResult struct {
11 | Address string `json:"address"`
12 | }
13 |
14 | func (r *GenesisPredeployResult) GetOutput() string {
15 | var buffer bytes.Buffer
16 |
17 | buffer.WriteString("\n[SMART CONTRACT PREDEPLOYMENT]\n")
18 |
19 | outputs := []string{
20 | fmt.Sprintf("Address|%s", r.Address),
21 | }
22 |
23 | buffer.WriteString(helper.FormatKV(outputs))
24 | buffer.WriteString("\n")
25 |
26 | return buffer.String()
27 | }
28 |
--------------------------------------------------------------------------------
/command/genesis/result.go:
--------------------------------------------------------------------------------
1 | package genesis
2 |
3 | import (
4 | "bytes"
5 | )
6 |
7 | type GenesisResult struct {
8 | Message string `json:"message"`
9 | }
10 |
11 | func (r *GenesisResult) GetOutput() string {
12 | var buffer bytes.Buffer
13 |
14 | buffer.WriteString("\n[GENESIS SUCCESS]\n")
15 | buffer.WriteString(r.Message)
16 |
17 | return buffer.String()
18 | }
19 |
--------------------------------------------------------------------------------
/command/ibft/candidates/ibft_candidates.go:
--------------------------------------------------------------------------------
1 | package candidates
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/command"
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | ibftOp "github.com/ExzoNetwork/ExzoCoin/consensus/ibft/proto"
9 | "github.com/spf13/cobra"
10 | empty "google.golang.org/protobuf/types/known/emptypb"
11 | )
12 |
13 | func GetCommand() *cobra.Command {
14 | return &cobra.Command{
15 | Use: "candidates",
16 | Short: "Queries the current set of proposed candidates, as well as candidates that have not been included yet",
17 | Run: runCommand,
18 | }
19 | }
20 |
21 | func runCommand(cmd *cobra.Command, _ []string) {
22 | outputter := command.InitializeOutputter(cmd)
23 | defer outputter.WriteOutput()
24 |
25 | candidatesResponse, err := getIBFTCandidates(helper.GetGRPCAddress(cmd))
26 | if err != nil {
27 | outputter.SetError(err)
28 |
29 | return
30 | }
31 |
32 | outputter.SetCommandResult(
33 | newIBFTCandidatesResult(candidatesResponse),
34 | )
35 | }
36 |
37 | func getIBFTCandidates(grpcAddress string) (*ibftOp.CandidatesResp, error) {
38 | client, err := helper.GetIBFTOperatorClientConnection(
39 | grpcAddress,
40 | )
41 | if err != nil {
42 | return nil, err
43 | }
44 |
45 | return client.Candidates(context.Background(), &empty.Empty{})
46 | }
47 |
--------------------------------------------------------------------------------
/command/ibft/candidates/result.go:
--------------------------------------------------------------------------------
1 | package candidates
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | ibftHelper "github.com/ExzoNetwork/ExzoCoin/command/ibft/helper"
9 | ibftOp "github.com/ExzoNetwork/ExzoCoin/consensus/ibft/proto"
10 | )
11 |
12 | type IBFTCandidate struct {
13 | Address string `json:"address"`
14 | Vote ibftHelper.Vote `json:"vote"`
15 | }
16 |
17 | type IBFTCandidatesResult struct {
18 | Candidates []IBFTCandidate `json:"candidates"`
19 | }
20 |
21 | func newIBFTCandidatesResult(resp *ibftOp.CandidatesResp) *IBFTCandidatesResult {
22 | res := &IBFTCandidatesResult{
23 | Candidates: make([]IBFTCandidate, len(resp.Candidates)),
24 | }
25 |
26 | for i, c := range resp.Candidates {
27 | res.Candidates[i].Address = c.Address
28 | res.Candidates[i].Vote = ibftHelper.BoolToVote(c.Auth)
29 | }
30 |
31 | return res
32 | }
33 |
34 | func (r *IBFTCandidatesResult) GetOutput() string {
35 | var buffer bytes.Buffer
36 |
37 | buffer.WriteString("\n[IBFT CANDIDATES]\n")
38 |
39 | if num := len(r.Candidates); num == 0 {
40 | buffer.WriteString("No candidates found")
41 | } else {
42 | buffer.WriteString(fmt.Sprintf("Number of candidates: %d\n\n", num))
43 | buffer.WriteString(formatCandidates(r.Candidates))
44 | }
45 |
46 | buffer.WriteString("\n")
47 |
48 | return buffer.String()
49 | }
50 |
51 | func formatCandidates(candidates []IBFTCandidate) string {
52 | generatedCandidates := make([]string, 0, len(candidates)+1)
53 |
54 | generatedCandidates = append(generatedCandidates, "Address|Vote")
55 | for _, c := range candidates {
56 | generatedCandidates = append(generatedCandidates, fmt.Sprintf("%s|%s", c.Address, c.Vote))
57 | }
58 |
59 | return helper.FormatKV(generatedCandidates)
60 | }
61 |
--------------------------------------------------------------------------------
/command/ibft/helper/vote.go:
--------------------------------------------------------------------------------
1 | package helper
2 |
3 | type Vote string
4 |
5 | const (
6 | VoteAdd = "ADD"
7 | VoteRemove = "REMOVE"
8 | )
9 |
10 | func BoolToVote(vote bool) Vote {
11 | if vote {
12 | return VoteAdd
13 | }
14 |
15 | return VoteRemove
16 | }
17 |
18 | func VoteToString(vote Vote) string {
19 | return string(vote)
20 | }
21 |
--------------------------------------------------------------------------------
/command/ibft/ibft.go:
--------------------------------------------------------------------------------
1 | package ibft
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
5 | "github.com/ExzoNetwork/ExzoCoin/command/ibft/candidates"
6 | "github.com/ExzoNetwork/ExzoCoin/command/ibft/propose"
7 | "github.com/ExzoNetwork/ExzoCoin/command/ibft/quorum"
8 | "github.com/ExzoNetwork/ExzoCoin/command/ibft/snapshot"
9 | "github.com/ExzoNetwork/ExzoCoin/command/ibft/status"
10 | _switch "github.com/ExzoNetwork/ExzoCoin/command/ibft/switch"
11 | "github.com/spf13/cobra"
12 | )
13 |
14 | func GetCommand() *cobra.Command {
15 | ibftCmd := &cobra.Command{
16 | Use: "ibft",
17 | Short: "Top level IBFT command for interacting with the IBFT consensus. Only accepts subcommands.",
18 | }
19 |
20 | helper.RegisterGRPCAddressFlag(ibftCmd)
21 |
22 | registerSubcommands(ibftCmd)
23 |
24 | return ibftCmd
25 | }
26 |
27 | func registerSubcommands(baseCmd *cobra.Command) {
28 | baseCmd.AddCommand(
29 | // ibft status
30 | status.GetCommand(),
31 | // ibft snapshot
32 | snapshot.GetCommand(),
33 | // ibft propose
34 | propose.GetCommand(),
35 | // ibft candidates
36 | candidates.GetCommand(),
37 | // ibft switch
38 | _switch.GetCommand(),
39 | // ibft quorum
40 | quorum.GetCommand(),
41 | )
42 | }
43 |
--------------------------------------------------------------------------------
/command/ibft/propose/ibft_propose.go:
--------------------------------------------------------------------------------
1 | package propose
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/command"
7 | "github.com/spf13/cobra"
8 |
9 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
10 | )
11 |
12 | func GetCommand() *cobra.Command {
13 | ibftSnapshotCmd := &cobra.Command{
14 | Use: "propose",
15 | Short: "Proposes a new candidate to be added or removed from the validator set",
16 | PreRunE: runPreRun,
17 | Run: runCommand,
18 | }
19 |
20 | setFlags(ibftSnapshotCmd)
21 |
22 | helper.SetRequiredFlags(ibftSnapshotCmd, params.getRequiredFlags())
23 |
24 | return ibftSnapshotCmd
25 | }
26 |
27 | func setFlags(cmd *cobra.Command) {
28 | cmd.Flags().StringVar(
29 | ¶ms.addressRaw,
30 | addressFlag,
31 | "",
32 | "the address of the account to be voted for",
33 | )
34 |
35 | cmd.Flags().StringVar(
36 | ¶ms.rawBLSPublicKey,
37 | blsFlag,
38 | "",
39 | "the BLS Public Key of the account to be voted for",
40 | )
41 |
42 | cmd.Flags().StringVar(
43 | ¶ms.vote,
44 | voteFlag,
45 | "",
46 | fmt.Sprintf(
47 | "requested change to the validator set. Possible values: [%s, %s]",
48 | authVote,
49 | dropVote,
50 | ),
51 | )
52 |
53 | cmd.MarkFlagsRequiredTogether(addressFlag, voteFlag)
54 | }
55 |
56 | func runPreRun(_ *cobra.Command, _ []string) error {
57 | if err := params.validateFlags(); err != nil {
58 | return err
59 | }
60 |
61 | return params.initRawParams()
62 | }
63 |
64 | func runCommand(cmd *cobra.Command, _ []string) {
65 | outputter := command.InitializeOutputter(cmd)
66 | defer outputter.WriteOutput()
67 |
68 | if err := params.proposeCandidate(helper.GetGRPCAddress(cmd)); err != nil {
69 | outputter.SetError(err)
70 |
71 | return
72 | }
73 |
74 | outputter.SetCommandResult(params.getResult())
75 | }
76 |
--------------------------------------------------------------------------------
/command/ibft/propose/result.go:
--------------------------------------------------------------------------------
1 | package propose
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | )
7 |
8 | type IBFTProposeResult struct {
9 | Address string `json:"-"`
10 | Vote string `json:"-"`
11 | }
12 |
13 | func (r *IBFTProposeResult) GetOutput() string {
14 | var buffer bytes.Buffer
15 |
16 | buffer.WriteString("\n[IBFT PROPOSE]\n")
17 | buffer.WriteString(r.Message())
18 | buffer.WriteString("\n")
19 |
20 | return buffer.String()
21 | }
22 |
23 | func (r *IBFTProposeResult) Message() string {
24 | if r.Vote == authVote {
25 | return fmt.Sprintf(
26 | "Successfully voted for the addition of address [%s] to the validator set",
27 | r.Address,
28 | )
29 | }
30 |
31 | return fmt.Sprintf(
32 | "Successfully voted for the removal of validator at address [%s] from the validator set",
33 | r.Address,
34 | )
35 | }
36 |
37 | func (r *IBFTProposeResult) MarshalJSON() ([]byte, error) {
38 | return []byte(fmt.Sprintf(`{"message": "%s"}`, r.Message())), nil
39 | }
40 |
--------------------------------------------------------------------------------
/command/ibft/quorum/ibft_quorum.go:
--------------------------------------------------------------------------------
1 | package quorum
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/command"
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | "github.com/spf13/cobra"
9 | )
10 |
11 | func GetCommand() *cobra.Command {
12 | ibftQuorumCmd := &cobra.Command{
13 | Use: "quorum",
14 | Short: "Specify the block number after which quorum optimal will be used for reaching consensus",
15 | PreRunE: runPreRun,
16 | Run: runCommand,
17 | }
18 |
19 | setFlags(ibftQuorumCmd)
20 | helper.SetRequiredFlags(ibftQuorumCmd, params.getRequiredFlags())
21 |
22 | return ibftQuorumCmd
23 | }
24 |
25 | func setFlags(cmd *cobra.Command) {
26 | cmd.Flags().StringVar(
27 | ¶ms.genesisPath,
28 | chainFlag,
29 | fmt.Sprintf("./%s", command.DefaultGenesisFileName),
30 | "the genesis file to update",
31 | )
32 |
33 | cmd.Flags().Uint64Var(
34 | ¶ms.from,
35 | fromFlag,
36 | 0,
37 | "the height to switch the quorum calculation",
38 | )
39 | }
40 |
41 | func runPreRun(_ *cobra.Command, _ []string) error {
42 | return params.initRawParams()
43 | }
44 |
45 | func runCommand(cmd *cobra.Command, _ []string) {
46 | outputter := command.InitializeOutputter(cmd)
47 | defer outputter.WriteOutput()
48 |
49 | if err := params.updateGenesisConfig(); err != nil {
50 | outputter.SetError(err)
51 |
52 | return
53 | }
54 |
55 | if err := params.overrideGenesisConfig(); err != nil {
56 | outputter.SetError(err)
57 |
58 | return
59 | }
60 |
61 | outputter.SetCommandResult(params.getResult())
62 | }
63 |
--------------------------------------------------------------------------------
/command/ibft/quorum/result.go:
--------------------------------------------------------------------------------
1 | package quorum
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | "github.com/ExzoNetwork/ExzoCoin/helper/common"
9 | )
10 |
11 | type IBFTQuorumResult struct {
12 | Chain string `json:"chain"`
13 | From common.JSONNumber `json:"from"`
14 | }
15 |
16 | func (r *IBFTQuorumResult) GetOutput() string {
17 | var buffer bytes.Buffer
18 |
19 | buffer.WriteString("\n[NEW IBFT QUORUM START]\n")
20 |
21 | outputs := []string{
22 | fmt.Sprintf("Chain|%s", r.Chain),
23 | fmt.Sprintf("From|%d", r.From.Value),
24 | }
25 |
26 | buffer.WriteString(helper.FormatKV(outputs))
27 | buffer.WriteString("\n")
28 |
29 | return buffer.String()
30 | }
31 |
--------------------------------------------------------------------------------
/command/ibft/snapshot/ibft_snapshot.go:
--------------------------------------------------------------------------------
1 | package snapshot
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/command"
5 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
6 | "github.com/spf13/cobra"
7 | )
8 |
9 | func GetCommand() *cobra.Command {
10 | ibftSnapshotCmd := &cobra.Command{
11 | Use: "snapshot",
12 | Short: "Returns the IBFT snapshot at the latest block number, unless a block number is specified",
13 | Run: runCommand,
14 | }
15 |
16 | setFlags(ibftSnapshotCmd)
17 |
18 | return ibftSnapshotCmd
19 | }
20 |
21 | func setFlags(cmd *cobra.Command) {
22 | cmd.Flags().IntVar(
23 | ¶ms.blockNumber,
24 | numberFlag,
25 | -1,
26 | "the block height (number) for the snapshot",
27 | )
28 | }
29 |
30 | func runCommand(cmd *cobra.Command, _ []string) {
31 | outputter := command.InitializeOutputter(cmd)
32 | defer outputter.WriteOutput()
33 |
34 | if err := params.initSnapshot(helper.GetGRPCAddress(cmd)); err != nil {
35 | outputter.SetError(err)
36 |
37 | return
38 | }
39 |
40 | result, err := newIBFTSnapshotResult(params.snapshot)
41 | if err != nil {
42 | outputter.SetError(err)
43 |
44 | return
45 | }
46 |
47 | outputter.SetCommandResult(result)
48 | }
49 |
--------------------------------------------------------------------------------
/command/ibft/snapshot/params.go:
--------------------------------------------------------------------------------
1 | package snapshot
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
7 | ibftOp "github.com/ExzoNetwork/ExzoCoin/consensus/ibft/proto"
8 | )
9 |
10 | const (
11 | numberFlag = "number"
12 | )
13 |
14 | var (
15 | params = &snapshotParams{}
16 | )
17 |
18 | type snapshotParams struct {
19 | blockNumber int
20 |
21 | snapshot *ibftOp.Snapshot
22 | }
23 |
24 | func (p *snapshotParams) initSnapshot(grpcAddress string) error {
25 | ibftClient, err := helper.GetIBFTOperatorClientConnection(grpcAddress)
26 | if err != nil {
27 | return err
28 | }
29 |
30 | snapshot, err := ibftClient.GetSnapshot(
31 | context.Background(),
32 | p.getSnapshotRequest(),
33 | )
34 | if err != nil {
35 | return err
36 | }
37 |
38 | p.snapshot = snapshot
39 |
40 | return nil
41 | }
42 |
43 | func (p *snapshotParams) getSnapshotRequest() *ibftOp.SnapshotReq {
44 | req := &ibftOp.SnapshotReq{
45 | Latest: true,
46 | }
47 |
48 | if p.blockNumber >= 0 {
49 | req.Latest = false
50 | req.Number = uint64(p.blockNumber)
51 | }
52 |
53 | return req
54 | }
55 |
--------------------------------------------------------------------------------
/command/ibft/status/ibft_status.go:
--------------------------------------------------------------------------------
1 | package status
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/command"
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | ibftOp "github.com/ExzoNetwork/ExzoCoin/consensus/ibft/proto"
9 | "github.com/spf13/cobra"
10 | empty "google.golang.org/protobuf/types/known/emptypb"
11 | )
12 |
13 | func GetCommand() *cobra.Command {
14 | return &cobra.Command{
15 | Use: "status",
16 | Short: "Returns the current validator key of the IBFT client",
17 | Run: runCommand,
18 | }
19 | }
20 |
21 | func runCommand(cmd *cobra.Command, _ []string) {
22 | outputter := command.InitializeOutputter(cmd)
23 | defer outputter.WriteOutput()
24 |
25 | statusResponse, err := getIBFTStatus(helper.GetGRPCAddress(cmd))
26 | if err != nil {
27 | outputter.SetError(err)
28 |
29 | return
30 | }
31 |
32 | outputter.SetCommandResult(&IBFTStatusResult{
33 | ValidatorKey: statusResponse.Key,
34 | })
35 | }
36 |
37 | func getIBFTStatus(grpcAddress string) (*ibftOp.IbftStatusResp, error) {
38 | client, err := helper.GetIBFTOperatorClientConnection(
39 | grpcAddress,
40 | )
41 | if err != nil {
42 | return nil, err
43 | }
44 |
45 | return client.Status(context.Background(), &empty.Empty{})
46 | }
47 |
--------------------------------------------------------------------------------
/command/ibft/status/result.go:
--------------------------------------------------------------------------------
1 | package status
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | )
9 |
10 | type IBFTStatusResult struct {
11 | ValidatorKey string `json:"validator_key"`
12 | }
13 |
14 | func (r *IBFTStatusResult) GetOutput() string {
15 | var buffer bytes.Buffer
16 |
17 | buffer.WriteString("\n[VALIDATOR STATUS]\n")
18 | buffer.WriteString(helper.FormatKV([]string{
19 | fmt.Sprintf("Validator key|%s", r.ValidatorKey),
20 | }))
21 | buffer.WriteString("\n")
22 |
23 | return buffer.String()
24 | }
25 |
--------------------------------------------------------------------------------
/command/ibft/switch/result.go:
--------------------------------------------------------------------------------
1 | package ibftswitch
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | "github.com/ExzoNetwork/ExzoCoin/consensus/ibft/fork"
9 | "github.com/ExzoNetwork/ExzoCoin/helper/common"
10 | "github.com/ExzoNetwork/ExzoCoin/validators"
11 | )
12 |
13 | type IBFTSwitchResult struct {
14 | Chain string `json:"chain"`
15 | Type fork.IBFTType `json:"type"`
16 | ValidatorType validators.ValidatorType `json:"validator_type"`
17 | From common.JSONNumber `json:"from"`
18 | Deployment *common.JSONNumber `json:"deployment,omitempty"`
19 | MaxValidatorCount common.JSONNumber `json:"maxValidatorCount"`
20 | MinValidatorCount common.JSONNumber `json:"minValidatorCount"`
21 | }
22 |
23 | func (r *IBFTSwitchResult) GetOutput() string {
24 | var buffer bytes.Buffer
25 |
26 | buffer.WriteString("\n[NEW IBFT FORK]\n")
27 |
28 | outputs := []string{
29 | fmt.Sprintf("Chain|%s", r.Chain),
30 | fmt.Sprintf("Type|%s", r.Type),
31 | fmt.Sprintf("ValidatorType|%s", r.ValidatorType),
32 | }
33 |
34 | if r.Deployment != nil {
35 | outputs = append(outputs, fmt.Sprintf("Deployment|%d", r.Deployment.Value))
36 | }
37 |
38 | outputs = append(outputs, fmt.Sprintf("From|%d", r.From.Value))
39 |
40 | if r.Type == fork.PoS {
41 | outputs = append(outputs,
42 | fmt.Sprintf("MaxValidatorCount|%d", r.MaxValidatorCount.Value),
43 | fmt.Sprintf("MinValidatorCount|%d", r.MinValidatorCount.Value),
44 | )
45 | }
46 |
47 | buffer.WriteString(helper.FormatKV(outputs))
48 | buffer.WriteString("\n")
49 |
50 | return buffer.String()
51 | }
52 |
--------------------------------------------------------------------------------
/command/json_output.go:
--------------------------------------------------------------------------------
1 | package command
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "os"
7 | )
8 |
9 | type JSONOutput struct {
10 | commonOutputFormatter
11 | }
12 |
13 | func (jo *JSONOutput) WriteOutput() {
14 | if jo.errorOutput != nil {
15 | _, _ = fmt.Fprintln(os.Stderr, jo.getErrorOutput())
16 |
17 | return
18 | }
19 |
20 | _, _ = fmt.Fprintln(os.Stdout, jo.getCommandOutput())
21 | }
22 |
23 | func newJSONOutput() *JSONOutput {
24 | return &JSONOutput{}
25 | }
26 |
27 | func (jo *JSONOutput) getErrorOutput() string {
28 | return marshalJSONToString(
29 | struct {
30 | Err string `json:"error"`
31 | }{
32 | Err: jo.errorOutput.Error(),
33 | },
34 | )
35 | }
36 |
37 | func (jo *JSONOutput) getCommandOutput() string {
38 | return marshalJSONToString(jo.commandOutput)
39 | }
40 |
41 | func marshalJSONToString(input interface{}) string {
42 | bytes, err := json.Marshal(input)
43 | if err != nil {
44 | return err.Error()
45 | }
46 |
47 | return string(bytes)
48 | }
49 |
--------------------------------------------------------------------------------
/command/license/license.go:
--------------------------------------------------------------------------------
1 | package license
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/command"
5 | "github.com/spf13/cobra"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/licenses"
8 | )
9 |
10 | func GetCommand() *cobra.Command {
11 | return &cobra.Command{
12 | Use: "license",
13 | Short: "Returns Polygon Edge license and dependency attributions",
14 | Args: cobra.NoArgs,
15 | Run: runCommand,
16 | }
17 | }
18 |
19 | func runCommand(cmd *cobra.Command, _ []string) {
20 | outputter := command.InitializeOutputter(cmd)
21 | defer outputter.WriteOutput()
22 |
23 | bsdLicenses, err := licenses.GetBSDLicenses()
24 | if err != nil {
25 | outputter.SetError(err)
26 |
27 | return
28 | }
29 |
30 | outputter.SetCommandResult(
31 | &LicenseResult{
32 | BSDLicenses: bsdLicenses,
33 | },
34 | )
35 | }
36 |
--------------------------------------------------------------------------------
/command/license/result.go:
--------------------------------------------------------------------------------
1 | package license
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/licenses"
8 | )
9 |
10 | type LicenseResult struct {
11 | BSDLicenses []licenses.DepLicense `json:"bsd_licenses"`
12 | }
13 |
14 | func (r *LicenseResult) GetOutput() string {
15 | var buffer bytes.Buffer
16 |
17 | buffer.WriteString("\n[LICENSE]\n\n")
18 | buffer.WriteString(licenses.License)
19 |
20 | buffer.WriteString("\n[DEPENDENCY ATTRIBUTIONS]\n\n")
21 |
22 | for idx, l := range r.BSDLicenses {
23 | // put a blank line between attributions
24 | if idx != 0 {
25 | buffer.WriteString("\n")
26 | }
27 |
28 | name := l.Name
29 | if l.Version != nil {
30 | name += " " + *l.Version
31 | }
32 |
33 | buffer.WriteString(fmt.Sprintf(
34 | " This product bundles %s,\n"+
35 | " which is available under a \"%s\" license.\n"+
36 | " For details, see %s.\n",
37 | name,
38 | l.Type,
39 | l.Path,
40 | ))
41 | }
42 |
43 | return buffer.String()
44 | }
45 |
--------------------------------------------------------------------------------
/command/monitor/result.go:
--------------------------------------------------------------------------------
1 | package monitor
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | "github.com/ExzoNetwork/ExzoCoin/server/proto"
9 | )
10 |
11 | const (
12 | eventAdded = "ADD BLOCK"
13 | eventRemoved = "REMOVE BLOCK"
14 | )
15 |
16 | type BlockchainEvent struct {
17 | Type string `json:"type"`
18 | Number int64 `json:"number"`
19 | Hash string `json:"hash"`
20 | }
21 |
22 | type BlockChainEvents struct {
23 | Added []BlockchainEvent `json:"added"`
24 | Removed []BlockchainEvent `json:"removed"`
25 | }
26 |
27 | type BlockEventResult struct {
28 | Events BlockChainEvents `json:"events"`
29 | }
30 |
31 | func NewBlockEventResult(e *proto.BlockchainEvent) *BlockEventResult {
32 | res := &BlockEventResult{
33 | Events: BlockChainEvents{
34 | Added: make([]BlockchainEvent, len(e.Added)),
35 | Removed: make([]BlockchainEvent, len(e.Removed)),
36 | },
37 | }
38 |
39 | for i, add := range e.Added {
40 | res.Events.Added[i].Type = eventAdded
41 | res.Events.Added[i].Number = add.Number
42 | res.Events.Added[i].Hash = add.Hash
43 | }
44 |
45 | for i, rem := range e.Removed {
46 | res.Events.Removed[i].Type = eventRemoved
47 | res.Events.Removed[i].Number = rem.Number
48 | res.Events.Removed[i].Hash = rem.Hash
49 | }
50 |
51 | return res
52 | }
53 |
54 | func (r *BlockEventResult) GetOutput() string {
55 | var buffer bytes.Buffer
56 |
57 | buffer.WriteString("\n[BLOCK EVENT]\n")
58 |
59 | for _, event := range r.getCombinedEvents() {
60 | buffer.WriteString(helper.FormatKV([]string{
61 | fmt.Sprintf("Event Type|%s", event.Type),
62 | fmt.Sprintf("Block Number|%d", event.Number),
63 | fmt.Sprintf("Block Hash|%s", event.Hash),
64 | }))
65 | }
66 |
67 | return buffer.String()
68 | }
69 |
70 | func (r *BlockEventResult) getCombinedEvents() []BlockchainEvent {
71 | events := append([]BlockchainEvent{}, r.Events.Added...)
72 |
73 | return append(events, r.Events.Removed...)
74 | }
75 |
--------------------------------------------------------------------------------
/command/output.go:
--------------------------------------------------------------------------------
1 | package command
2 |
3 | import (
4 | "github.com/spf13/cobra"
5 | )
6 |
7 | // OutputFormatter is the standardized interface all output formatters
8 | // should use
9 | type OutputFormatter interface {
10 | // getErrorOutput returns the CLI command error
11 | getErrorOutput() string
12 |
13 | // getCommandOutput returns the CLI command output
14 | getCommandOutput() string
15 |
16 | // SetError sets the encountered error
17 | SetError(err error)
18 |
19 | // SetCommandResult sets the result of the command execution
20 | SetCommandResult(result CommandResult)
21 |
22 | // WriteOutput writes the result / error output
23 | WriteOutput()
24 | }
25 |
26 | type CommandResult interface {
27 | GetOutput() string
28 | }
29 |
30 | func shouldOutputJSON(baseCmd *cobra.Command) bool {
31 | return baseCmd.Flag(JSONOutputFlag).Changed
32 | }
33 |
34 | func InitializeOutputter(cmd *cobra.Command) OutputFormatter {
35 | if shouldOutputJSON(cmd) {
36 | return newJSONOutput()
37 | }
38 |
39 | return newCLIOutput()
40 | }
41 |
--------------------------------------------------------------------------------
/command/peers/add/params.go:
--------------------------------------------------------------------------------
1 | package add
2 |
3 | import (
4 | "context"
5 | "errors"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/command"
8 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
9 | "github.com/ExzoNetwork/ExzoCoin/server/proto"
10 | )
11 |
12 | var (
13 | params = &addParams{
14 | addedPeers: make([]string, 0),
15 | addErrors: make([]string, 0),
16 | }
17 | )
18 |
19 | var (
20 | errInvalidAddresses = errors.New("at least 1 peer address is required")
21 | )
22 |
23 | const (
24 | addrFlag = "addr"
25 | )
26 |
27 | type addParams struct {
28 | peerAddresses []string
29 |
30 | systemClient proto.SystemClient
31 |
32 | addedPeers []string
33 | addErrors []string
34 | }
35 |
36 | func (p *addParams) getRequiredFlags() []string {
37 | return []string{
38 | addrFlag,
39 | }
40 | }
41 |
42 | func (p *addParams) validateFlags() error {
43 | if len(p.peerAddresses) < 1 {
44 | return errInvalidAddresses
45 | }
46 |
47 | return nil
48 | }
49 |
50 | func (p *addParams) initSystemClient(grpcAddress string) error {
51 | systemClient, err := helper.GetSystemClientConnection(grpcAddress)
52 | if err != nil {
53 | return err
54 | }
55 |
56 | p.systemClient = systemClient
57 |
58 | return nil
59 | }
60 |
61 | func (p *addParams) addPeers() {
62 | for _, address := range p.peerAddresses {
63 | if addErr := p.addPeer(address); addErr != nil {
64 | p.addErrors = append(p.addErrors, addErr.Error())
65 |
66 | continue
67 | }
68 |
69 | p.addedPeers = append(p.addedPeers, address)
70 | }
71 | }
72 |
73 | func (p *addParams) addPeer(peerAddress string) error {
74 | if _, err := p.systemClient.PeersAdd(
75 | context.Background(),
76 | &proto.PeersAddRequest{
77 | Id: peerAddress,
78 | },
79 | ); err != nil {
80 | return err
81 | }
82 |
83 | return nil
84 | }
85 |
86 | func (p *addParams) getResult() command.CommandResult {
87 | return &PeersAddResult{
88 | NumRequested: len(p.peerAddresses),
89 | NumAdded: len(p.addedPeers),
90 | Peers: p.addedPeers,
91 | Errors: p.addErrors,
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/command/peers/add/peers_add.go:
--------------------------------------------------------------------------------
1 | package add
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/command"
5 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
6 | "github.com/spf13/cobra"
7 | )
8 |
9 | func GetCommand() *cobra.Command {
10 | peersAddCmd := &cobra.Command{
11 | Use: "add",
12 | Short: "Adds new peers to the peer list, using the peer's libp2p address",
13 | PreRunE: runPreRun,
14 | Run: runCommand,
15 | }
16 |
17 | setFlags(peersAddCmd)
18 | helper.SetRequiredFlags(peersAddCmd, params.getRequiredFlags())
19 |
20 | return peersAddCmd
21 | }
22 |
23 | func setFlags(cmd *cobra.Command) {
24 | cmd.Flags().StringArrayVar(
25 | ¶ms.peerAddresses,
26 | addrFlag,
27 | []string{},
28 | "the libp2p addresses of the peers",
29 | )
30 | }
31 |
32 | func runPreRun(_ *cobra.Command, _ []string) error {
33 | return params.validateFlags()
34 | }
35 |
36 | func runCommand(cmd *cobra.Command, _ []string) {
37 | outputter := command.InitializeOutputter(cmd)
38 | defer outputter.WriteOutput()
39 |
40 | if err := params.initSystemClient(helper.GetGRPCAddress(cmd)); err != nil {
41 | outputter.SetError(err)
42 |
43 | return
44 | }
45 |
46 | params.addPeers()
47 |
48 | outputter.SetCommandResult(params.getResult())
49 | }
50 |
--------------------------------------------------------------------------------
/command/peers/add/result.go:
--------------------------------------------------------------------------------
1 | package add
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | )
9 |
10 | type PeersAddResult struct {
11 | NumRequested int `json:"num_requested"`
12 | NumAdded int `json:"num_added"`
13 | Peers []string `json:"peers"`
14 | Errors []string `json:"errors"`
15 | }
16 |
17 | func (r *PeersAddResult) GetOutput() string {
18 | var buffer bytes.Buffer
19 |
20 | buffer.WriteString("\n[PEERS ADDED]\n")
21 | buffer.WriteString(helper.FormatKV([]string{
22 | fmt.Sprintf("Peers listed|%d", r.NumRequested), // The number of peers the user wanted to add
23 | fmt.Sprintf("Peers added|%d", r.NumAdded), // The number of peers that have been added
24 | }))
25 |
26 | if len(r.Peers) > 0 {
27 | buffer.WriteString("\n\n[LIST OF ADDED PEERS]\n")
28 | buffer.WriteString(helper.FormatList(r.Peers))
29 | }
30 |
31 | if len(r.Errors) > 0 {
32 | buffer.WriteString("\n\n[ERRORS]\n")
33 | buffer.WriteString(helper.FormatList(r.Errors))
34 | }
35 |
36 | buffer.WriteString("\n")
37 |
38 | return buffer.String()
39 | }
40 |
--------------------------------------------------------------------------------
/command/peers/list/peers_list.go:
--------------------------------------------------------------------------------
1 | package list
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/command"
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | "github.com/ExzoNetwork/ExzoCoin/server/proto"
9 | "github.com/spf13/cobra"
10 | empty "google.golang.org/protobuf/types/known/emptypb"
11 | )
12 |
13 | func GetCommand() *cobra.Command {
14 | peersListCmd := &cobra.Command{
15 | Use: "list",
16 | Short: "Returns the list of connected peers, including the current node",
17 | Run: runCommand,
18 | }
19 |
20 | return peersListCmd
21 | }
22 |
23 | func runCommand(cmd *cobra.Command, _ []string) {
24 | outputter := command.InitializeOutputter(cmd)
25 | defer outputter.WriteOutput()
26 |
27 | peersList, err := getPeersList(helper.GetGRPCAddress(cmd))
28 | if err != nil {
29 | outputter.SetError(err)
30 |
31 | return
32 | }
33 |
34 | outputter.SetCommandResult(
35 | newPeersListResult(peersList.Peers),
36 | )
37 | }
38 |
39 | func getPeersList(grpcAddress string) (*proto.PeersListResponse, error) {
40 | client, err := helper.GetSystemClientConnection(grpcAddress)
41 | if err != nil {
42 | return nil, err
43 | }
44 |
45 | return client.PeersList(context.Background(), &empty.Empty{})
46 | }
47 |
--------------------------------------------------------------------------------
/command/peers/list/result.go:
--------------------------------------------------------------------------------
1 | package list
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | "github.com/ExzoNetwork/ExzoCoin/server/proto"
9 | )
10 |
11 | type PeersListResult struct {
12 | Peers []string `json:"peers"`
13 | }
14 |
15 | func newPeersListResult(peers []*proto.Peer) *PeersListResult {
16 | resultPeers := make([]string, len(peers))
17 | for i, p := range peers {
18 | resultPeers[i] = p.Id
19 | }
20 |
21 | return &PeersListResult{
22 | Peers: resultPeers,
23 | }
24 | }
25 |
26 | func (r *PeersListResult) GetOutput() string {
27 | var buffer bytes.Buffer
28 |
29 | buffer.WriteString("\n[PEERS LIST]\n")
30 |
31 | if len(r.Peers) == 0 {
32 | buffer.WriteString("No peers found")
33 | } else {
34 | buffer.WriteString(fmt.Sprintf("Number of peers: %d\n\n", len(r.Peers)))
35 |
36 | rows := make([]string, len(r.Peers))
37 | for i, p := range r.Peers {
38 | rows[i] = fmt.Sprintf("[%d]|%s", i, p)
39 | }
40 | buffer.WriteString(helper.FormatKV(rows))
41 | }
42 |
43 | buffer.WriteString("\n")
44 |
45 | return buffer.String()
46 | }
47 |
--------------------------------------------------------------------------------
/command/peers/peers.go:
--------------------------------------------------------------------------------
1 | package peers
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
5 | "github.com/ExzoNetwork/ExzoCoin/command/peers/add"
6 | "github.com/ExzoNetwork/ExzoCoin/command/peers/list"
7 | "github.com/ExzoNetwork/ExzoCoin/command/peers/status"
8 | "github.com/spf13/cobra"
9 | )
10 |
11 | func GetCommand() *cobra.Command {
12 | peersCmd := &cobra.Command{
13 | Use: "peers",
14 | Short: "Top level command for interacting with the network peers. Only accepts subcommands.",
15 | }
16 |
17 | helper.RegisterGRPCAddressFlag(peersCmd)
18 |
19 | registerSubcommands(peersCmd)
20 |
21 | return peersCmd
22 | }
23 |
24 | func registerSubcommands(baseCmd *cobra.Command) {
25 | baseCmd.AddCommand(
26 | // peers status
27 | status.GetCommand(),
28 | // peers list
29 | list.GetCommand(),
30 | // peers add
31 | add.GetCommand(),
32 | )
33 | }
34 |
--------------------------------------------------------------------------------
/command/peers/status/params.go:
--------------------------------------------------------------------------------
1 | package status
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/command"
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | "github.com/ExzoNetwork/ExzoCoin/server/proto"
9 | )
10 |
11 | var (
12 | params = &statusParams{}
13 | )
14 |
15 | const (
16 | peerIDFlag = "peer-id"
17 | )
18 |
19 | type statusParams struct {
20 | peerID string
21 |
22 | peerStatus *proto.Peer
23 | }
24 |
25 | func (p *statusParams) getRequiredFlags() []string {
26 | return []string{
27 | peerIDFlag,
28 | }
29 | }
30 |
31 | func (p *statusParams) initPeerInfo(grpcAddress string) error {
32 | systemClient, err := helper.GetSystemClientConnection(grpcAddress)
33 | if err != nil {
34 | return err
35 | }
36 |
37 | peerStatus, err := systemClient.PeersStatus(
38 | context.Background(),
39 | &proto.PeersStatusRequest{
40 | Id: p.peerID,
41 | },
42 | )
43 | if err != nil {
44 | return err
45 | }
46 |
47 | p.peerStatus = peerStatus
48 |
49 | return nil
50 | }
51 |
52 | func (p *statusParams) getResult() command.CommandResult {
53 | return &PeersStatusResult{
54 | ID: p.peerStatus.Id,
55 | Protocols: p.peerStatus.Protocols,
56 | Addresses: p.peerStatus.Addrs,
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/command/peers/status/peers_status.go:
--------------------------------------------------------------------------------
1 | package status
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/command"
5 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
6 | "github.com/spf13/cobra"
7 | )
8 |
9 | func GetCommand() *cobra.Command {
10 | peersStatusCmd := &cobra.Command{
11 | Use: "status",
12 | Short: "Returns the status of the specified peer, using the libp2p ID of the peer node",
13 | Run: runCommand,
14 | }
15 |
16 | setFlags(peersStatusCmd)
17 | helper.SetRequiredFlags(peersStatusCmd, params.getRequiredFlags())
18 |
19 | return peersStatusCmd
20 | }
21 |
22 | func setFlags(cmd *cobra.Command) {
23 | cmd.Flags().StringVar(
24 | ¶ms.peerID,
25 | peerIDFlag,
26 | "",
27 | "libp2p node ID of a specific peer within p2p network",
28 | )
29 | }
30 |
31 | func runCommand(cmd *cobra.Command, _ []string) {
32 | outputter := command.InitializeOutputter(cmd)
33 | defer outputter.WriteOutput()
34 |
35 | if err := params.initPeerInfo(helper.GetGRPCAddress(cmd)); err != nil {
36 | outputter.SetError(err)
37 |
38 | return
39 | }
40 |
41 | outputter.SetCommandResult(params.getResult())
42 | }
43 |
--------------------------------------------------------------------------------
/command/peers/status/result.go:
--------------------------------------------------------------------------------
1 | package status
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | )
9 |
10 | type PeersStatusResult struct {
11 | ID string `json:"id"`
12 | Protocols []string `json:"protocols"`
13 | Addresses []string `json:"addresses"`
14 | }
15 |
16 | func (r *PeersStatusResult) GetOutput() string {
17 | var buffer bytes.Buffer
18 |
19 | buffer.WriteString("\n[PEER STATUS]\n")
20 | buffer.WriteString(helper.FormatKV([]string{
21 | fmt.Sprintf("ID|%s", r.ID),
22 | fmt.Sprintf("Protocols|%s", r.Protocols),
23 | fmt.Sprintf("Addresses|%s", r.Addresses),
24 | }))
25 | buffer.WriteString("\n")
26 |
27 | return buffer.String()
28 | }
29 |
--------------------------------------------------------------------------------
/command/root/root.go:
--------------------------------------------------------------------------------
1 | package root
2 |
3 | import (
4 | "fmt"
5 | "os"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/command/backup"
8 | "github.com/ExzoNetwork/ExzoCoin/command/genesis"
9 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
10 | "github.com/ExzoNetwork/ExzoCoin/command/ibft"
11 | "github.com/ExzoNetwork/ExzoCoin/command/license"
12 | "github.com/ExzoNetwork/ExzoCoin/command/monitor"
13 | "github.com/ExzoNetwork/ExzoCoin/command/peers"
14 | "github.com/ExzoNetwork/ExzoCoin/command/secrets"
15 | "github.com/ExzoNetwork/ExzoCoin/command/server"
16 | "github.com/ExzoNetwork/ExzoCoin/command/status"
17 | "github.com/ExzoNetwork/ExzoCoin/command/txpool"
18 | "github.com/ExzoNetwork/ExzoCoin/command/version"
19 | "github.com/ExzoNetwork/ExzoCoin/command/whitelist"
20 | "github.com/spf13/cobra"
21 | )
22 |
23 | type RootCommand struct {
24 | baseCmd *cobra.Command
25 | }
26 |
27 | func NewRootCommand() *RootCommand {
28 | rootCommand := &RootCommand{
29 | baseCmd: &cobra.Command{
30 | Short: "Polygon Edge is a framework for building Ethereum-compatible Blockchain networks",
31 | },
32 | }
33 |
34 | helper.RegisterJSONOutputFlag(rootCommand.baseCmd)
35 |
36 | rootCommand.registerSubCommands()
37 |
38 | return rootCommand
39 | }
40 |
41 | func (rc *RootCommand) registerSubCommands() {
42 | rc.baseCmd.AddCommand(
43 | version.GetCommand(),
44 | txpool.GetCommand(),
45 | status.GetCommand(),
46 | secrets.GetCommand(),
47 | peers.GetCommand(),
48 | monitor.GetCommand(),
49 | ibft.GetCommand(),
50 | backup.GetCommand(),
51 | genesis.GetCommand(),
52 | server.GetCommand(),
53 | whitelist.GetCommand(),
54 | license.GetCommand(),
55 | )
56 | }
57 |
58 | func (rc *RootCommand) Execute() {
59 | if err := rc.baseCmd.Execute(); err != nil {
60 | _, _ = fmt.Fprintln(os.Stderr, err)
61 |
62 | os.Exit(1)
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/command/secrets/generate/result.go:
--------------------------------------------------------------------------------
1 | package generate
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | )
9 |
10 | type SecretsGenerateResult struct {
11 | ServiceType string `json:"service_type"`
12 | ServerURL string `json:"server_url"`
13 | AccessToken string `json:"access_token"`
14 | NodeName string `json:"node_name"`
15 | Namespace string `json:"namespace"`
16 | Extra string `json:"extra"`
17 | }
18 |
19 | func (r *SecretsGenerateResult) GetOutput() string {
20 | var buffer bytes.Buffer
21 |
22 | buffer.WriteString("\n[SECRETS GENERATE]\n")
23 | buffer.WriteString(helper.FormatKV([]string{
24 | fmt.Sprintf("Service Type|%s", r.ServiceType),
25 | fmt.Sprintf("Server URL|%s", r.ServerURL),
26 | fmt.Sprintf("Access Token|%s", r.AccessToken),
27 | fmt.Sprintf("Node Name|%s", r.NodeName),
28 | fmt.Sprintf("Namespace|%s", r.Namespace),
29 | fmt.Sprintf("Extra|%s", r.Extra),
30 | }))
31 | buffer.WriteString("\n")
32 |
33 | return buffer.String()
34 | }
35 |
--------------------------------------------------------------------------------
/command/secrets/generate/secrets_generate.go:
--------------------------------------------------------------------------------
1 | package generate
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/command"
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | "github.com/spf13/cobra"
9 |
10 | "github.com/ExzoNetwork/ExzoCoin/secrets"
11 | )
12 |
13 | func GetCommand() *cobra.Command {
14 | secretsGenerateCmd := &cobra.Command{
15 | Use: "generate",
16 | Short: "Initializes the secrets manager configuration in the provided directory.",
17 | Run: runCommand,
18 | }
19 |
20 | setFlags(secretsGenerateCmd)
21 | helper.SetRequiredFlags(secretsGenerateCmd, params.getRequiredFlags())
22 |
23 | return secretsGenerateCmd
24 | }
25 |
26 | func setFlags(cmd *cobra.Command) {
27 | cmd.Flags().StringVar(
28 | ¶ms.dir,
29 | dirFlag,
30 | defaultConfigFileName,
31 | "the directory for the secrets manager configuration file",
32 | )
33 |
34 | cmd.Flags().StringVar(
35 | ¶ms.token,
36 | tokenFlag,
37 | "",
38 | "the access token for the service",
39 | )
40 |
41 | cmd.Flags().StringVar(
42 | ¶ms.serverURL,
43 | serverURLFlag,
44 | "",
45 | "the server URL for the service",
46 | )
47 |
48 | cmd.Flags().StringVar(
49 | ¶ms.serviceType,
50 | typeFlag,
51 | string(secrets.HashicorpVault),
52 | fmt.Sprintf(
53 | "the type of the secrets manager. Available types: %s, %s and %s",
54 | secrets.HashicorpVault,
55 | secrets.AWSSSM,
56 | secrets.GCPSSM,
57 | ),
58 | )
59 |
60 | cmd.Flags().StringVar(
61 | ¶ms.name,
62 | nameFlag,
63 | defaultNodeName,
64 | "the name of the node for on-service record keeping",
65 | )
66 |
67 | cmd.Flags().StringVar(
68 | ¶ms.namespace,
69 | namespaceFlag,
70 | defaultNamespace,
71 | "the namespace for the service",
72 | )
73 |
74 | cmd.Flags().StringVar(
75 | ¶ms.extra,
76 | extraFlag,
77 | "",
78 | "Specifies the extra fields map in string format 'key1=val1,key2=val2'",
79 | )
80 | }
81 |
82 | func runCommand(cmd *cobra.Command, _ []string) {
83 | outputter := command.InitializeOutputter(cmd)
84 | defer outputter.WriteOutput()
85 |
86 | if err := params.writeSecretsConfig(); err != nil {
87 | outputter.SetError(err)
88 |
89 | return
90 | }
91 |
92 | outputter.SetCommandResult(params.getResult())
93 | }
94 |
--------------------------------------------------------------------------------
/command/secrets/init/result.go:
--------------------------------------------------------------------------------
1 | package init
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/command"
8 |
9 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
10 | "github.com/ExzoNetwork/ExzoCoin/types"
11 | )
12 |
13 | type Results []command.CommandResult
14 |
15 | func (r Results) GetOutput() string {
16 | var buffer bytes.Buffer
17 |
18 | for _, result := range r {
19 | buffer.WriteString(result.GetOutput())
20 | }
21 |
22 | return buffer.String()
23 | }
24 |
25 | type SecretsInitResult struct {
26 | Address types.Address `json:"address"`
27 | BLSPubkey string `json:"bls_pubkey"`
28 | NodeID string `json:"node_id"`
29 | }
30 |
31 | func (r *SecretsInitResult) GetOutput() string {
32 | var buffer bytes.Buffer
33 |
34 | vals := make([]string, 0, 3)
35 |
36 | vals = append(
37 | vals,
38 | fmt.Sprintf("Public key (address)|%s", r.Address.String()),
39 | )
40 |
41 | if r.BLSPubkey != "" {
42 | vals = append(
43 | vals,
44 | fmt.Sprintf("BLS Public key|%s", r.BLSPubkey),
45 | )
46 | }
47 |
48 | vals = append(vals, fmt.Sprintf("Node ID|%s", r.NodeID))
49 |
50 | buffer.WriteString("\n[SECRETS INIT]\n")
51 | buffer.WriteString(helper.FormatKV(vals))
52 | buffer.WriteString("\n")
53 |
54 | return buffer.String()
55 | }
56 |
--------------------------------------------------------------------------------
/command/secrets/output/result.go:
--------------------------------------------------------------------------------
1 | package output
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | )
9 |
10 | // SecretsOutputAllResults for default output case
11 | type SecretsOutputAllResult struct {
12 | Address string `json:"address"`
13 | BLSPubkey string `json:"bls"`
14 | NodeID string `json:"node_id"`
15 | }
16 |
17 | // SecretsOutputNodeIDResults for `--node` output case
18 | type SecretsOutputNodeIDResult struct {
19 | NodeID string `json:"node_id"`
20 | }
21 |
22 | // SecretsOutputBLSResults for `--bls` output case
23 | type SecretsOutputBLSResult struct {
24 | BLSPubkey string `json:"bls"`
25 | }
26 |
27 | // SecretsOutputValidatorResult for `--validator` output case
28 | type SecretsOutputValidatorResult struct {
29 | Address string `json:"address"`
30 | }
31 |
32 | func (r *SecretsOutputNodeIDResult) GetOutput() string {
33 | return r.NodeID
34 | }
35 |
36 | func (r *SecretsOutputValidatorResult) GetOutput() string {
37 | return r.Address
38 | }
39 |
40 | func (r *SecretsOutputBLSResult) GetOutput() string {
41 | return r.BLSPubkey
42 | }
43 |
44 | func (r *SecretsOutputAllResult) GetOutput() string {
45 | var buffer bytes.Buffer
46 |
47 | vals := make([]string, 0, 3)
48 |
49 | vals = append(
50 | vals,
51 | fmt.Sprintf("Public key (address)|%s", r.Address),
52 | )
53 |
54 | vals = append(
55 | vals,
56 | fmt.Sprintf("BLS Public key|%s", r.BLSPubkey),
57 | )
58 |
59 | vals = append(
60 | vals,
61 | fmt.Sprintf("Node ID|%s", r.NodeID),
62 | )
63 |
64 | buffer.WriteString("\n[SECRETS OUTPUT]\n")
65 | buffer.WriteString(helper.FormatKV(vals))
66 |
67 | buffer.WriteString("\n")
68 |
69 | return buffer.String()
70 | }
71 |
--------------------------------------------------------------------------------
/command/secrets/output/secrets_output.go:
--------------------------------------------------------------------------------
1 | package output
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/command"
5 | "github.com/spf13/cobra"
6 | )
7 |
8 | func GetCommand() *cobra.Command {
9 | secretsOutputCmd := &cobra.Command{
10 | Use: "output",
11 | Short: "Outputs validator key address and public network key from the provided Secrets Manager",
12 | PreRunE: runPreRun,
13 | Run: runCommand,
14 | }
15 |
16 | setFlags(secretsOutputCmd)
17 |
18 | return secretsOutputCmd
19 | }
20 |
21 | func setFlags(cmd *cobra.Command) {
22 | cmd.Flags().StringVar(
23 | ¶ms.dataDir,
24 | dataDirFlag,
25 | "",
26 | "the directory for the Polygon Edge data if the local FS is used",
27 | )
28 |
29 | cmd.Flags().StringVar(
30 | ¶ms.configPath,
31 | configFlag,
32 | "",
33 | "the path to the SecretsManager config file, "+
34 | "if omitted, the local FS secrets manager is used",
35 | )
36 |
37 | cmd.Flags().BoolVar(
38 | ¶ms.outputBLS,
39 | blsFlag,
40 | false,
41 | "output only the BLS public key "+
42 | "from the provided secrets manager",
43 | )
44 |
45 | cmd.Flags().BoolVar(
46 | ¶ms.outputNodeID,
47 | nodeIDFlag,
48 | false,
49 | "output only the node id "+
50 | "from the provided secrets manager",
51 | )
52 |
53 | cmd.Flags().BoolVar(
54 | ¶ms.outputValidator,
55 | validatorFlag,
56 | false,
57 | "output only the validator key address "+
58 | "from the provided secrets manager",
59 | )
60 |
61 | cmd.MarkFlagsMutuallyExclusive(dataDirFlag, configFlag)
62 | cmd.MarkFlagsMutuallyExclusive(nodeIDFlag, validatorFlag, blsFlag)
63 | }
64 |
65 | func runPreRun(_ *cobra.Command, _ []string) error {
66 | return params.validateFlags()
67 | }
68 |
69 | func runCommand(cmd *cobra.Command, _ []string) {
70 | outputter := command.InitializeOutputter(cmd)
71 | defer outputter.WriteOutput()
72 |
73 | if err := params.initSecrets(); err != nil {
74 | outputter.SetError(err)
75 |
76 | return
77 | }
78 |
79 | outputter.SetCommandResult(params.getResult())
80 | }
81 |
--------------------------------------------------------------------------------
/command/secrets/secrets.go:
--------------------------------------------------------------------------------
1 | package secrets
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
5 | "github.com/ExzoNetwork/ExzoCoin/command/secrets/generate"
6 | initCmd "github.com/ExzoNetwork/ExzoCoin/command/secrets/init"
7 | "github.com/ExzoNetwork/ExzoCoin/command/secrets/output"
8 | "github.com/spf13/cobra"
9 | )
10 |
11 | func GetCommand() *cobra.Command {
12 | secretsCmd := &cobra.Command{
13 | Use: "secrets",
14 | Short: "Top level SecretsManager command for interacting with secrets functionality. Only accepts subcommands.",
15 | }
16 |
17 | helper.RegisterGRPCAddressFlag(secretsCmd)
18 |
19 | registerSubcommands(secretsCmd)
20 |
21 | return secretsCmd
22 | }
23 |
24 | func registerSubcommands(baseCmd *cobra.Command) {
25 | baseCmd.AddCommand(
26 | // secrets init
27 | initCmd.GetCommand(),
28 | // secrets generate
29 | generate.GetCommand(),
30 | // secrets output public data
31 | output.GetCommand(),
32 | )
33 | }
34 |
--------------------------------------------------------------------------------
/command/server/export/export.go:
--------------------------------------------------------------------------------
1 | package export
2 |
3 | import (
4 | "encoding/json"
5 | "errors"
6 | "fmt"
7 | "os"
8 |
9 | "github.com/ExzoNetwork/ExzoCoin/command"
10 | "github.com/ExzoNetwork/ExzoCoin/command/server/config"
11 | "github.com/spf13/cobra"
12 | "gopkg.in/yaml.v3"
13 | )
14 |
15 | func GetCommand() *cobra.Command {
16 | configCmd := &cobra.Command{
17 | Use: "export",
18 | Short: "export default-config.yaml file with default parameters that can be used to run the server",
19 | Run: runGenerateConfigCommand,
20 | }
21 |
22 | setFlags(configCmd)
23 |
24 | return configCmd
25 | }
26 |
27 | func setFlags(cmd *cobra.Command) {
28 | cmd.Flags().StringVar(
29 | ¶mFlagValues.FileType,
30 | fileTypeFlag,
31 | "yaml",
32 | "file type of exported config file (yaml or json)",
33 | )
34 | }
35 |
36 | func runGenerateConfigCommand(cmd *cobra.Command, _ []string) {
37 | outputter := command.InitializeOutputter(cmd)
38 | defer outputter.WriteOutput()
39 |
40 | if err := generateConfig(*config.DefaultConfig()); err != nil {
41 | outputter.SetError(err)
42 |
43 | return
44 | }
45 |
46 | outputter.SetCommandResult(&cmdResult{
47 | CommandOutput: "Configuration file successfully exported",
48 | })
49 | }
50 |
51 | func generateConfig(config config.Config) error {
52 | config.Network.MaxPeers = -1
53 | config.Network.MaxInboundPeers = -1
54 | config.Network.MaxOutboundPeers = -1
55 |
56 | var (
57 | data []byte
58 | err error
59 | )
60 |
61 | switch paramFlagValues.FileType {
62 | case "yaml", "yml":
63 | data, err = yaml.Marshal(config)
64 | case "json":
65 | data, err = json.MarshalIndent(config, "", " ")
66 | default:
67 | return errors.New("invalid file type, only yaml and json are supported")
68 | }
69 |
70 | if err != nil {
71 | return fmt.Errorf("could not marshal config struct, %w", err)
72 | }
73 |
74 | if err := os.WriteFile(
75 | fmt.Sprintf("default-config.%s", paramFlagValues.FileType),
76 | data,
77 | os.ModePerm); err != nil {
78 | return errors.New("could not create and write config file")
79 | }
80 |
81 | return nil
82 | }
83 |
--------------------------------------------------------------------------------
/command/server/export/params.go:
--------------------------------------------------------------------------------
1 | package export
2 |
3 | const (
4 | fileTypeFlag = "type"
5 | )
6 |
7 | type exportParams struct {
8 | FileType string
9 | }
10 |
11 | var (
12 | paramFlagValues = &exportParams{}
13 | )
14 |
--------------------------------------------------------------------------------
/command/server/export/result.go:
--------------------------------------------------------------------------------
1 | package export
2 |
3 | import "bytes"
4 |
5 | type cmdResult struct {
6 | CommandOutput string `json:"export_result"`
7 | }
8 |
9 | func (c *cmdResult) GetOutput() string {
10 | var buffer bytes.Buffer
11 |
12 | buffer.WriteString("\n[EXPORT SUCCESS]\n")
13 | buffer.WriteString(c.CommandOutput + "\n")
14 |
15 | return buffer.String()
16 | }
17 |
--------------------------------------------------------------------------------
/command/status/result.go:
--------------------------------------------------------------------------------
1 | package status
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | )
9 |
10 | type StatusResult struct {
11 | ChainID int64 `json:"chain_id"`
12 | CurrentBlockNumber int64 `json:"current_block_number"`
13 | CurrentBlockHash string `json:"current_block_hash"`
14 | LibP2PAddress string `json:"libp2p_address"`
15 | }
16 |
17 | func (r *StatusResult) GetOutput() string {
18 | var buffer bytes.Buffer
19 |
20 | buffer.WriteString("\n[CLIENT STATUS]\n")
21 | buffer.WriteString(helper.FormatKV([]string{
22 | fmt.Sprintf("Network (Chain ID)|%d", r.ChainID),
23 | fmt.Sprintf("Current Block Number (base 10)|%d", r.CurrentBlockNumber),
24 | fmt.Sprintf("Current Block Hash|%s", r.CurrentBlockHash),
25 | fmt.Sprintf("Libp2p Address|%s", r.LibP2PAddress),
26 | }))
27 |
28 | return buffer.String()
29 | }
30 |
--------------------------------------------------------------------------------
/command/status/status.go:
--------------------------------------------------------------------------------
1 | package status
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/command"
7 | "github.com/golang/protobuf/ptypes/empty"
8 | "github.com/spf13/cobra"
9 |
10 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
11 | "github.com/ExzoNetwork/ExzoCoin/server/proto"
12 | )
13 |
14 | func GetCommand() *cobra.Command {
15 | statusCmd := &cobra.Command{
16 | Use: "status",
17 | Short: "Returns the status of the Polygon Edge client",
18 | Args: cobra.NoArgs,
19 | Run: runCommand,
20 | }
21 |
22 | helper.RegisterGRPCAddressFlag(statusCmd)
23 |
24 | return statusCmd
25 | }
26 |
27 | func runCommand(cmd *cobra.Command, _ []string) {
28 | outputter := command.InitializeOutputter(cmd)
29 | defer outputter.WriteOutput()
30 |
31 | statusResponse, err := getSystemStatus(helper.GetGRPCAddress(cmd))
32 | if err != nil {
33 | outputter.SetError(err)
34 |
35 | return
36 | }
37 |
38 | outputter.SetCommandResult(&StatusResult{
39 | ChainID: statusResponse.Network,
40 | CurrentBlockNumber: statusResponse.Current.Number,
41 | CurrentBlockHash: statusResponse.Current.Hash,
42 | LibP2PAddress: statusResponse.P2PAddr,
43 | })
44 | }
45 |
46 | func getSystemStatus(grpcAddress string) (*proto.ServerStatus, error) {
47 | client, err := helper.GetSystemClientConnection(
48 | grpcAddress,
49 | )
50 | if err != nil {
51 | return nil, err
52 | }
53 |
54 | return client.GetStatus(context.Background(), &empty.Empty{})
55 | }
56 |
--------------------------------------------------------------------------------
/command/txpool/status/result.go:
--------------------------------------------------------------------------------
1 | package status
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | )
9 |
10 | type TxPoolStatusResult struct {
11 | Transactions uint64 `json:"transactions"`
12 | }
13 |
14 | func (r *TxPoolStatusResult) GetOutput() string {
15 | var buffer bytes.Buffer
16 |
17 | buffer.WriteString("\n[TXPOOL STATUS]\n")
18 | buffer.WriteString(helper.FormatKV([]string{
19 | fmt.Sprintf("Number of transactions in pool:|%d", r.Transactions),
20 | }))
21 | buffer.WriteString("\n")
22 |
23 | return buffer.String()
24 | }
25 |
--------------------------------------------------------------------------------
/command/txpool/status/txpool_status.go:
--------------------------------------------------------------------------------
1 | package status
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/command"
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | "github.com/spf13/cobra"
9 |
10 | txpoolOp "github.com/ExzoNetwork/ExzoCoin/txpool/proto"
11 | empty "google.golang.org/protobuf/types/known/emptypb"
12 | )
13 |
14 | func GetCommand() *cobra.Command {
15 | return &cobra.Command{
16 | Use: "status",
17 | Short: "Returns the number of transactions in the transaction pool",
18 | Run: runCommand,
19 | }
20 | }
21 |
22 | func runCommand(cmd *cobra.Command, _ []string) {
23 | outputter := command.InitializeOutputter(cmd)
24 | defer outputter.WriteOutput()
25 |
26 | statusResponse, err := getTxPoolStatus(helper.GetGRPCAddress(cmd))
27 | if err != nil {
28 | outputter.SetError(err)
29 |
30 | return
31 | }
32 |
33 | outputter.SetCommandResult(&TxPoolStatusResult{
34 | Transactions: statusResponse.Length,
35 | })
36 | }
37 |
38 | func getTxPoolStatus(grpcAddress string) (*txpoolOp.TxnPoolStatusResp, error) {
39 | client, err := helper.GetTxPoolClientConnection(
40 | grpcAddress,
41 | )
42 | if err != nil {
43 | return nil, err
44 | }
45 |
46 | return client.Status(context.Background(), &empty.Empty{})
47 | }
48 |
--------------------------------------------------------------------------------
/command/txpool/subscribe/params.go:
--------------------------------------------------------------------------------
1 | package subscribe
2 |
3 | import "github.com/ExzoNetwork/ExzoCoin/txpool/proto"
4 |
5 | var (
6 | params = &subscribeParams{}
7 | )
8 |
9 | var (
10 | addedFlag = "added"
11 | promotedFlag = "promoted"
12 | demotedFlag = "demoted"
13 | enqueuedFlag = "enqueued"
14 | droppedFlag = "dropped"
15 | prunedPromotedFlag = "pruned-promoted"
16 | prunedEnqueuedFlag = "pruned-enqueued"
17 | )
18 |
19 | type subscribeParams struct {
20 | eventSubscriptionMap map[proto.EventType]*bool
21 | supportedEvents []proto.EventType
22 | }
23 |
24 | func (sp *subscribeParams) initEventMap() {
25 | falseRaw := false
26 | sp.eventSubscriptionMap = map[proto.EventType]*bool{
27 | proto.EventType_ADDED: &falseRaw,
28 | proto.EventType_ENQUEUED: &falseRaw,
29 | proto.EventType_PROMOTED: &falseRaw,
30 | proto.EventType_DROPPED: &falseRaw,
31 | proto.EventType_DEMOTED: &falseRaw,
32 | proto.EventType_PRUNED_PROMOTED: &falseRaw,
33 | proto.EventType_PRUNED_ENQUEUED: &falseRaw,
34 | }
35 | }
36 |
37 | func (sp *subscribeParams) init() {
38 | sp.setSpecifiedEvents()
39 |
40 | if !sp.areEventsSpecified() {
41 | sp.setAllEvents()
42 | }
43 | }
44 |
45 | func (sp *subscribeParams) setSpecifiedEvents() {
46 | sp.supportedEvents = make([]proto.EventType, 0)
47 |
48 | for eventType, eventIsSupported := range sp.eventSubscriptionMap {
49 | if *eventIsSupported {
50 | sp.supportedEvents = append(sp.supportedEvents, eventType)
51 | }
52 | }
53 | }
54 |
55 | func (sp *subscribeParams) areEventsSpecified() bool {
56 | return len(sp.supportedEvents) != 0
57 | }
58 |
59 | func (sp *subscribeParams) setAllEvents() {
60 | sp.supportedEvents = []proto.EventType{
61 | proto.EventType_ADDED,
62 | proto.EventType_ENQUEUED,
63 | proto.EventType_PROMOTED,
64 | proto.EventType_DROPPED,
65 | proto.EventType_DEMOTED,
66 | proto.EventType_PRUNED_PROMOTED,
67 | proto.EventType_PRUNED_ENQUEUED,
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/command/txpool/subscribe/result.go:
--------------------------------------------------------------------------------
1 | package subscribe
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | txpoolProto "github.com/ExzoNetwork/ExzoCoin/txpool/proto"
9 | )
10 |
11 | type TxPoolEventResult struct {
12 | EventType txpoolProto.EventType `json:"event_type"`
13 | TxHash string `json:"tx_hash"`
14 | }
15 |
16 | func (r *TxPoolEventResult) GetOutput() string {
17 | var buffer bytes.Buffer
18 |
19 | buffer.WriteString("\n[TXPOOL EVENT]\n")
20 | buffer.WriteString(helper.FormatKV([]string{
21 | fmt.Sprintf("TYPE|%s", r.EventType),
22 | fmt.Sprintf("HASH|%s", r.TxHash),
23 | }))
24 | buffer.WriteString("\n")
25 |
26 | return buffer.String()
27 | }
28 |
--------------------------------------------------------------------------------
/command/txpool/txpool.go:
--------------------------------------------------------------------------------
1 | package txpool
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
5 | "github.com/ExzoNetwork/ExzoCoin/command/txpool/status"
6 | "github.com/ExzoNetwork/ExzoCoin/command/txpool/subscribe"
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func GetCommand() *cobra.Command {
11 | txPoolCmd := &cobra.Command{
12 | Use: "txpool",
13 | Short: "Top level command for interacting with the transaction pool. Only accepts subcommands.",
14 | }
15 |
16 | helper.RegisterGRPCAddressFlag(txPoolCmd)
17 |
18 | registerSubcommands(txPoolCmd)
19 |
20 | return txPoolCmd
21 | }
22 |
23 | func registerSubcommands(baseCmd *cobra.Command) {
24 | baseCmd.AddCommand(
25 | // txpool status
26 | status.GetCommand(),
27 | // txpool subscribe
28 | subscribe.GetCommand(),
29 | )
30 | }
31 |
--------------------------------------------------------------------------------
/command/version/result.go:
--------------------------------------------------------------------------------
1 | package version
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/command/helper"
8 | )
9 |
10 | type VersionResult struct {
11 | Version string `json:"version"`
12 | Commit string `json:"commit"`
13 | Branch string `json:"branch"`
14 | BuildTime string `json:"buildTime"`
15 | }
16 |
17 | func (r *VersionResult) GetOutput() string {
18 | var buffer bytes.Buffer
19 |
20 | buffer.WriteString("\n[VERSION INFO]\n")
21 | buffer.WriteString(helper.FormatKV([]string{
22 | fmt.Sprintf("Release version|%s", r.Version),
23 | fmt.Sprintf("Git branch|%s", r.Branch),
24 | fmt.Sprintf("Commit hash|%s", r.Commit),
25 | fmt.Sprintf("Build time|%s", r.BuildTime),
26 | }))
27 |
28 | return buffer.String()
29 | }
30 |
--------------------------------------------------------------------------------
/command/version/version.go:
--------------------------------------------------------------------------------
1 | package version
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/command"
5 | "github.com/ExzoNetwork/ExzoCoin/versioning"
6 | "github.com/spf13/cobra"
7 | )
8 |
9 | func GetCommand() *cobra.Command {
10 | return &cobra.Command{
11 | Use: "version",
12 | Short: "Returns the current Polygon Edge version",
13 | Args: cobra.NoArgs,
14 | Run: runCommand,
15 | }
16 | }
17 |
18 | func runCommand(cmd *cobra.Command, _ []string) {
19 | outputter := command.InitializeOutputter(cmd)
20 | defer outputter.WriteOutput()
21 |
22 | outputter.SetCommandResult(
23 | &VersionResult{
24 | Version: versioning.Version,
25 | Commit: versioning.Commit,
26 | Branch: versioning.Branch,
27 | BuildTime: versioning.BuildTime,
28 | },
29 | )
30 | }
31 |
--------------------------------------------------------------------------------
/command/whitelist/deployment/deployment.go:
--------------------------------------------------------------------------------
1 | package deployment
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/command"
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func GetCommand() *cobra.Command {
11 | deploymentCmd := &cobra.Command{
12 | Use: "deployment",
13 | Short: "Top level command for updating smart contract deployment whitelist. Only accepts subcommands",
14 | PreRunE: runPreRun,
15 | Run: runCommand,
16 | }
17 |
18 | setFlags(deploymentCmd)
19 |
20 | return deploymentCmd
21 | }
22 |
23 | func setFlags(cmd *cobra.Command) {
24 | cmd.Flags().StringVar(
25 | ¶ms.genesisPath,
26 | chainFlag,
27 | fmt.Sprintf("./%s", command.DefaultGenesisFileName),
28 | "the genesis file to update",
29 | )
30 | cmd.Flags().StringArrayVar(
31 | ¶ms.addAddressRaw,
32 | addAddressFlag,
33 | []string{},
34 | "adds a new address to the contract deployment whitelist",
35 | )
36 |
37 | cmd.Flags().StringArrayVar(
38 | ¶ms.removeAddressRaw,
39 | removeAddressFlag,
40 | []string{},
41 | "removes a new address from the contract deployment whitelist",
42 | )
43 | }
44 |
45 | func runPreRun(_ *cobra.Command, _ []string) error {
46 | return params.initRawParams()
47 | }
48 |
49 | func runCommand(cmd *cobra.Command, _ []string) {
50 | outputter := command.InitializeOutputter(cmd)
51 | defer outputter.WriteOutput()
52 |
53 | if err := params.updateGenesisConfig(); err != nil {
54 | outputter.SetError(err)
55 |
56 | return
57 | }
58 |
59 | if err := params.overrideGenesisConfig(); err != nil {
60 | outputter.SetError(err)
61 |
62 | return
63 | }
64 |
65 | outputter.SetCommandResult(params.getResult())
66 | }
67 |
--------------------------------------------------------------------------------
/command/whitelist/deployment/result.go:
--------------------------------------------------------------------------------
1 | package deployment
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/types"
8 | )
9 |
10 | type DeploymentResult struct {
11 | AddAddresses []types.Address `json:"addAddress,omitempty"`
12 | RemoveAddresses []types.Address `json:"removeAddress,omitempty"`
13 | Whitelist []types.Address `json:"whitelist"`
14 | }
15 |
16 | func (r *DeploymentResult) GetOutput() string {
17 | var buffer bytes.Buffer
18 |
19 | buffer.WriteString("\n[CONTRACT DEPLOYMENT WHITELIST]\n\n")
20 |
21 | if len(r.AddAddresses) != 0 {
22 | buffer.WriteString(fmt.Sprintf("Added addresses: %s,\n", r.AddAddresses))
23 | }
24 |
25 | if len(r.RemoveAddresses) != 0 {
26 | buffer.WriteString(fmt.Sprintf("Removed addresses: %s,\n", r.RemoveAddresses))
27 | }
28 |
29 | buffer.WriteString(fmt.Sprintf("Contract deployment whitelist : %s,\n", r.Whitelist))
30 |
31 | return buffer.String()
32 | }
33 |
--------------------------------------------------------------------------------
/command/whitelist/show/params.go:
--------------------------------------------------------------------------------
1 | package show
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/chain"
7 | "github.com/ExzoNetwork/ExzoCoin/command"
8 | "github.com/ExzoNetwork/ExzoCoin/helper/config"
9 | "github.com/ExzoNetwork/ExzoCoin/types"
10 | )
11 |
12 | const (
13 | chainFlag = "chain"
14 | )
15 |
16 | var (
17 | params = &showParams{}
18 | )
19 |
20 | type showParams struct {
21 | // genesis file path
22 | genesisPath string
23 |
24 | // deployment whitelist
25 | whitelists Whitelists
26 | }
27 |
28 | type Whitelists struct {
29 | deployment []types.Address
30 | }
31 |
32 | func (p *showParams) initRawParams() error {
33 | // init genesis configuration
34 | if err := p.initWhitelists(); err != nil {
35 | return err
36 | }
37 |
38 | return nil
39 | }
40 |
41 | func (p *showParams) initWhitelists() error {
42 | // import genesis configuration
43 | genesisConfig, err := chain.Import(p.genesisPath)
44 | if err != nil {
45 | return fmt.Errorf(
46 | "failed to load chain config from %s: %w",
47 | p.genesisPath,
48 | err,
49 | )
50 | }
51 |
52 | // fetch whitelists
53 | deploymentWhitelist, err := config.GetDeploymentWhitelist(genesisConfig)
54 | if err != nil {
55 | return err
56 | }
57 |
58 | // set whitelists
59 | p.whitelists = Whitelists{
60 | deployment: deploymentWhitelist,
61 | }
62 |
63 | return nil
64 | }
65 |
66 | func (p *showParams) getResult() command.CommandResult {
67 | result := &ShowResult{
68 | Whitelists: p.whitelists,
69 | }
70 |
71 | return result
72 | }
73 |
--------------------------------------------------------------------------------
/command/whitelist/show/result.go:
--------------------------------------------------------------------------------
1 | package show
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | )
7 |
8 | type ShowResult struct {
9 | Whitelists Whitelists
10 | }
11 |
12 | func (r *ShowResult) GetOutput() string {
13 | var buffer bytes.Buffer
14 |
15 | buffer.WriteString("\n[WHITELISTS]\n\n")
16 |
17 | buffer.WriteString(fmt.Sprintf("Contract deployment whitelist : %s,\n", r.Whitelists.deployment))
18 |
19 | return buffer.String()
20 | }
21 |
--------------------------------------------------------------------------------
/command/whitelist/show/show.go:
--------------------------------------------------------------------------------
1 | package show
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/command"
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | func GetCommand() *cobra.Command {
11 | showCmd := &cobra.Command{
12 | Use: "show",
13 | Short: "Displays whitelist information",
14 | PreRunE: runPreRun,
15 | Run: runCommand,
16 | }
17 |
18 | setFlags(showCmd)
19 |
20 | return showCmd
21 | }
22 |
23 | func setFlags(cmd *cobra.Command) {
24 | cmd.Flags().StringVar(
25 | ¶ms.genesisPath,
26 | chainFlag,
27 | fmt.Sprintf("./%s", command.DefaultGenesisFileName),
28 | "the genesis file to update",
29 | )
30 | }
31 |
32 | func runPreRun(_ *cobra.Command, _ []string) error {
33 | return params.initRawParams()
34 | }
35 |
36 | func runCommand(cmd *cobra.Command, _ []string) {
37 | outputter := command.InitializeOutputter(cmd)
38 | defer outputter.WriteOutput()
39 |
40 | outputter.SetCommandResult(params.getResult())
41 | }
42 |
--------------------------------------------------------------------------------
/command/whitelist/whitelist.go:
--------------------------------------------------------------------------------
1 | package whitelist
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/command/whitelist/deployment"
5 | "github.com/ExzoNetwork/ExzoCoin/command/whitelist/show"
6 | "github.com/spf13/cobra"
7 | )
8 |
9 | func GetCommand() *cobra.Command {
10 | whitelistCmd := &cobra.Command{
11 | Use: "whitelist",
12 | Short: "Top level command for modifying the Polygon Edge whitelists within the config. Only accepts subcommands.",
13 | }
14 |
15 | registerSubcommands(whitelistCmd)
16 |
17 | return whitelistCmd
18 | }
19 |
20 | func registerSubcommands(baseCmd *cobra.Command) {
21 | baseCmd.AddCommand(
22 | deployment.GetCommand(),
23 | show.GetCommand(),
24 | )
25 | }
26 |
--------------------------------------------------------------------------------
/consensus/dummy/dummy.go:
--------------------------------------------------------------------------------
1 | package dummy
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/blockchain"
5 | "github.com/ExzoNetwork/ExzoCoin/consensus"
6 | "github.com/ExzoNetwork/ExzoCoin/helper/progress"
7 | "github.com/ExzoNetwork/ExzoCoin/state"
8 | "github.com/ExzoNetwork/ExzoCoin/txpool"
9 | "github.com/ExzoNetwork/ExzoCoin/types"
10 | "github.com/hashicorp/go-hclog"
11 | )
12 |
13 | type Dummy struct {
14 | logger hclog.Logger
15 | notifyCh chan struct{}
16 | closeCh chan struct{}
17 | txpool *txpool.TxPool
18 | blockchain *blockchain.Blockchain
19 | executor *state.Executor
20 | }
21 |
22 | func Factory(params *consensus.Params) (consensus.Consensus, error) {
23 | logger := params.Logger.Named("dummy")
24 |
25 | d := &Dummy{
26 | logger: logger,
27 | notifyCh: make(chan struct{}),
28 | closeCh: make(chan struct{}),
29 | blockchain: params.Blockchain,
30 | executor: params.Executor,
31 | txpool: params.TxPool,
32 | }
33 |
34 | return d, nil
35 | }
36 |
37 | // Initialize initializes the consensus
38 | func (d *Dummy) Initialize() error {
39 | d.txpool.SetSealing(true)
40 |
41 | return nil
42 | }
43 |
44 | func (d *Dummy) Start() error {
45 | go d.run()
46 |
47 | return nil
48 | }
49 |
50 | func (d *Dummy) VerifyHeader(header *types.Header) error {
51 | // All blocks are valid
52 | return nil
53 | }
54 |
55 | func (d *Dummy) ProcessHeaders(headers []*types.Header) error {
56 | return nil
57 | }
58 |
59 | func (d *Dummy) GetBlockCreator(header *types.Header) (types.Address, error) {
60 | return types.BytesToAddress(header.Miner), nil
61 | }
62 |
63 | // PreCommitState a hook to be called before finalizing state transition on inserting block
64 | func (d *Dummy) PreCommitState(_header *types.Header, _txn *state.Transition) error {
65 | return nil
66 | }
67 |
68 | func (d *Dummy) GetSyncProgression() *progress.Progression {
69 | return nil
70 | }
71 |
72 | func (d *Dummy) Close() error {
73 | close(d.closeCh)
74 |
75 | return nil
76 | }
77 |
78 | func (d *Dummy) run() {
79 | d.logger.Info("started")
80 | // do nothing
81 | <-d.closeCh
82 | }
83 |
--------------------------------------------------------------------------------
/consensus/ibft/consensus.go:
--------------------------------------------------------------------------------
1 | package ibft
2 |
3 | import (
4 | "context"
5 | "sync"
6 |
7 | "github.com/0xPolygon/go-ibft/core"
8 | )
9 |
10 | // IBFTConsensus is a convenience wrapper for the go-ibft package
11 | type IBFTConsensus struct {
12 | *core.IBFT
13 |
14 | wg sync.WaitGroup
15 |
16 | cancelSequence context.CancelFunc
17 | }
18 |
19 | func newIBFT(
20 | logger core.Logger,
21 | backend core.Backend,
22 | transport core.Transport,
23 | ) *IBFTConsensus {
24 | return &IBFTConsensus{
25 | IBFT: core.NewIBFT(logger, backend, transport),
26 | wg: sync.WaitGroup{},
27 | }
28 | }
29 |
30 | // runSequence starts the underlying consensus mechanism for the given height.
31 | // It may be called by a single thread at any given time
32 | func (c *IBFTConsensus) runSequence(height uint64) <-chan struct{} {
33 | done := make(chan struct{})
34 | ctx, cancel := context.WithCancel(context.Background())
35 |
36 | c.cancelSequence = cancel
37 |
38 | c.wg.Add(1)
39 |
40 | go func() {
41 | defer func() {
42 | cancel()
43 | c.wg.Done()
44 | close(done)
45 | }()
46 |
47 | c.RunSequence(ctx, height)
48 | }()
49 |
50 | return done
51 | }
52 |
53 | // stopSequence terminates the running IBFT sequence gracefully and waits for it to return
54 | func (c *IBFTConsensus) stopSequence() {
55 | c.cancelSequence()
56 | c.wg.Wait()
57 | }
58 |
--------------------------------------------------------------------------------
/consensus/ibft/fork/helper.go:
--------------------------------------------------------------------------------
1 | package fork
2 |
3 | import (
4 | "encoding/json"
5 | "os"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/validators/store/snapshot"
8 | )
9 |
10 | // loadSnapshotMetadata loads Metadata from file
11 | func loadSnapshotMetadata(path string) (*snapshot.SnapshotMetadata, error) {
12 | var meta *snapshot.SnapshotMetadata
13 | if err := readDataStore(path, &meta); err != nil {
14 | return nil, err
15 | }
16 |
17 | return meta, nil
18 | }
19 |
20 | // loadSnapshots loads Snapshots from file
21 | func loadSnapshots(path string) ([]*snapshot.Snapshot, error) {
22 | snaps := []*snapshot.Snapshot{}
23 | if err := readDataStore(path, &snaps); err != nil {
24 | return nil, err
25 | }
26 |
27 | return snaps, nil
28 | }
29 |
30 | // readDataStore attempts to read the specific file from file storage
31 | // return nil if the file doesn't exist
32 | func readDataStore(path string, obj interface{}) error {
33 | if _, err := os.Stat(path); os.IsNotExist(err) {
34 | return nil
35 | }
36 |
37 | data, err := os.ReadFile(path)
38 | if err != nil {
39 | return err
40 | }
41 |
42 | if err := json.Unmarshal(data, obj); err != nil {
43 | return err
44 | }
45 |
46 | return nil
47 | }
48 |
49 | // writeDataStore attempts to write the specific file to file storage
50 | func writeDataStore(path string, obj interface{}) error {
51 | data, err := json.Marshal(obj)
52 | if err != nil {
53 | return err
54 | }
55 |
56 | if err := os.WriteFile(path, data, os.ModePerm); err != nil {
57 | return err
58 | }
59 |
60 | return nil
61 | }
62 |
--------------------------------------------------------------------------------
/consensus/ibft/fork/type.go:
--------------------------------------------------------------------------------
1 | package fork
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/validators/store"
7 | )
8 |
9 | // Define the type of the IBFT consensus
10 | type IBFTType string
11 |
12 | const (
13 | // PoA defines the Proof of Authority IBFT type,
14 | // where the validator set is changed through voting / pre-set in genesis
15 | PoA IBFTType = "PoA"
16 |
17 | // PoS defines the Proof of Stake IBFT type,
18 | // where the validator set it changed through staking on the Staking Smart Contract
19 | PoS IBFTType = "PoS"
20 | )
21 |
22 | // ibftTypes is the map used for easy string -> IBFTType lookups
23 | var ibftTypes = map[string]IBFTType{
24 | "PoA": PoA,
25 | "PoS": PoS,
26 | }
27 |
28 | // ibftTypesToSourceType defines validator set type used under each IBFT Type
29 | // Right now each IBFT Type is correspond one-to-one with ValidatorStore
30 | // In other words, PoA always uses SnapshotValidatorStore while PoS uses ContractValidatorStore
31 | // By definition, PoA can fetch validators from ContractValidatorStore
32 | var ibftTypesToSourceType = map[IBFTType]store.SourceType{
33 | PoA: store.Snapshot,
34 | PoS: store.Contract,
35 | }
36 |
37 | // String is a helper method for casting a IBFTType to a string representation
38 | func (t IBFTType) String() string {
39 | return string(t)
40 | }
41 |
42 | // ParseIBFTType converts a ibftType string representation to a IBFTType
43 | func ParseIBFTType(ibftType string) (IBFTType, error) {
44 | // Check if the cast is possible
45 | castType, ok := ibftTypes[ibftType]
46 | if !ok {
47 | return castType, fmt.Errorf("invalid IBFT type %s", ibftType)
48 | }
49 |
50 | return castType, nil
51 | }
52 |
--------------------------------------------------------------------------------
/consensus/ibft/fork/type_test.go:
--------------------------------------------------------------------------------
1 | package fork
2 |
3 | import (
4 | "errors"
5 | "testing"
6 |
7 | testHelper "github.com/ExzoNetwork/ExzoCoin/helper/tests"
8 | "github.com/stretchr/testify/assert"
9 | )
10 |
11 | func TestIBFTTypeString(t *testing.T) {
12 | t.Parallel()
13 |
14 | cases := map[IBFTType]string{
15 | PoA: "PoA",
16 | PoS: "PoS",
17 | }
18 |
19 | for typ, expected := range cases {
20 | assert.Equal(
21 | t,
22 | expected,
23 | typ.String(),
24 | )
25 | }
26 | }
27 |
28 | func TestParseIBFTType(t *testing.T) {
29 | t.Parallel()
30 |
31 | tests := []struct {
32 | value string
33 | res IBFTType
34 | err error
35 | }{
36 | {
37 | value: "PoA",
38 | res: PoA,
39 | err: nil,
40 | },
41 | {
42 | value: "PoS",
43 | res: PoS,
44 | err: nil,
45 | },
46 | {
47 | value: "hoge",
48 | res: IBFTType(""),
49 | err: errors.New("invalid IBFT type hoge"),
50 | },
51 | }
52 |
53 | for _, test := range tests {
54 | test := test
55 |
56 | t.Run(test.value, func(t *testing.T) {
57 | t.Parallel()
58 |
59 | res, err := ParseIBFTType(test.value)
60 |
61 | assert.Equal(
62 | t,
63 | test.res,
64 | res,
65 | )
66 |
67 | testHelper.AssertErrorMessageContains(
68 | t,
69 | test.err,
70 | err,
71 | )
72 | })
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/consensus/ibft/helper_test.go:
--------------------------------------------------------------------------------
1 | package ibft
2 |
3 | import (
4 | "crypto/ecdsa"
5 | "strconv"
6 | "testing"
7 |
8 | "github.com/ExzoNetwork/ExzoCoin/crypto"
9 | "github.com/ExzoNetwork/ExzoCoin/types"
10 | "github.com/ExzoNetwork/ExzoCoin/validators"
11 | )
12 |
13 | type testerAccount struct {
14 | alias string
15 | priv *ecdsa.PrivateKey
16 | }
17 |
18 | func (t *testerAccount) Address() types.Address {
19 | return crypto.PubKeyToAddress(&t.priv.PublicKey)
20 | }
21 |
22 | type testerAccountPool struct {
23 | t *testing.T
24 | accounts []*testerAccount
25 | }
26 |
27 | func newTesterAccountPool(t *testing.T, num ...int) *testerAccountPool {
28 | t.Helper()
29 |
30 | pool := &testerAccountPool{
31 | t: t,
32 | accounts: []*testerAccount{},
33 | }
34 |
35 | if len(num) == 1 {
36 | for i := 0; i < num[0]; i++ {
37 | key, _ := crypto.GenerateECDSAKey()
38 |
39 | pool.accounts = append(pool.accounts, &testerAccount{
40 | alias: strconv.Itoa(i),
41 | priv: key,
42 | })
43 | }
44 | }
45 |
46 | return pool
47 | }
48 |
49 | func (ap *testerAccountPool) add(accounts ...string) {
50 | ap.t.Helper()
51 |
52 | for _, account := range accounts {
53 | if acct := ap.get(account); acct != nil {
54 | continue
55 | }
56 |
57 | priv, err := crypto.GenerateECDSAKey()
58 | if err != nil {
59 | panic("BUG: Failed to generate crypto key")
60 | }
61 |
62 | ap.accounts = append(ap.accounts, &testerAccount{
63 | alias: account,
64 | priv: priv,
65 | })
66 | }
67 | }
68 |
69 | func (ap *testerAccountPool) get(name string) *testerAccount {
70 | ap.t.Helper()
71 |
72 | for _, i := range ap.accounts {
73 | if i.alias == name {
74 | return i
75 | }
76 | }
77 |
78 | return nil
79 | }
80 |
81 | func (ap *testerAccountPool) ValidatorSet() validators.Validators {
82 | ap.t.Helper()
83 |
84 | v := validators.NewECDSAValidatorSet()
85 | for _, i := range ap.accounts {
86 | _ = v.Add(&validators.ECDSAValidator{
87 | Address: i.Address(),
88 | })
89 | }
90 |
91 | return v
92 | }
93 |
--------------------------------------------------------------------------------
/consensus/ibft/proto/ibft_operator.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package v1;
4 |
5 | option go_package = "/consensus/ibft/proto";
6 |
7 | import "google/protobuf/empty.proto";
8 |
9 | service IbftOperator {
10 | rpc GetSnapshot(SnapshotReq) returns (Snapshot);
11 | rpc Propose(Candidate) returns (google.protobuf.Empty);
12 | rpc Candidates(google.protobuf.Empty) returns (CandidatesResp);
13 | rpc Status(google.protobuf.Empty) returns (IbftStatusResp);
14 | }
15 |
16 | message IbftStatusResp {
17 | string key = 1;
18 | }
19 |
20 | message SnapshotReq {
21 | bool latest = 1;
22 | uint64 number = 2;
23 | }
24 |
25 | message Snapshot {
26 | repeated Validator validators = 1;
27 |
28 | uint64 number = 2;
29 |
30 | string hash = 3;
31 |
32 | repeated Vote votes = 4;
33 |
34 | message Validator {
35 | string type = 1;
36 | string address = 2;
37 | bytes data = 3;
38 | }
39 |
40 | message Vote {
41 | string validator = 1;
42 | string proposed = 2;
43 | bool auth = 3;
44 | }
45 | }
46 |
47 | message ProposeReq {
48 | string address = 1;
49 | bool auth = 2;
50 | }
51 |
52 | message CandidatesResp {
53 | repeated Candidate candidates = 1;
54 | }
55 |
56 | message Candidate {
57 | string address = 1;
58 | bytes bls_pubkey = 2;
59 | bool auth = 3;
60 | }
61 |
--------------------------------------------------------------------------------
/consensus/ibft/signer/key_manager.go:
--------------------------------------------------------------------------------
1 | package signer
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/types"
5 | "github.com/ExzoNetwork/ExzoCoin/validators"
6 | )
7 |
8 | // KeyManager is a delegated module that signs data
9 | type KeyManager interface {
10 | // Type returns Validator type signer supports
11 | Type() validators.ValidatorType
12 | // Address returns an address of signer
13 | Address() types.Address
14 | // NewEmptyValidators creates empty validator collection the Signer expects
15 | NewEmptyValidators() validators.Validators
16 | // NewEmptyCommittedSeals creates empty committed seals the Signer expects
17 | NewEmptyCommittedSeals() Seals
18 | // SignProposerSeal creates a signature for ProposerSeal
19 | SignProposerSeal(hash []byte) ([]byte, error)
20 | // SignCommittedSeal creates a signature for committed seal
21 | SignCommittedSeal(hash []byte) ([]byte, error)
22 | // VerifyCommittedSeal verifies a committed seal
23 | VerifyCommittedSeal(vals validators.Validators, signer types.Address, sig, hash []byte) error
24 | // GenerateCommittedSeals creates CommittedSeals from committed seals
25 | GenerateCommittedSeals(sealsByValidator map[types.Address][]byte, vals validators.Validators) (Seals, error)
26 | // VerifyCommittedSeals verifies CommittedSeals
27 | VerifyCommittedSeals(seals Seals, hash []byte, vals validators.Validators) (int, error)
28 | // SignIBFTMessage signs for arbitrary bytes message
29 | SignIBFTMessage(msg []byte) ([]byte, error)
30 | // Ecrecover recovers address from signature and message
31 | Ecrecover(sig []byte, msg []byte) (types.Address, error)
32 | }
33 |
--------------------------------------------------------------------------------
/consensus/ibft/state_test.go:
--------------------------------------------------------------------------------
1 | package ibft
2 |
3 | import (
4 | "strconv"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestState_FaultyNodes(t *testing.T) {
11 | cases := []struct {
12 | Network, Faulty uint64
13 | }{
14 | {1, 0},
15 | {2, 0},
16 | {3, 0},
17 | {4, 1},
18 | {5, 1},
19 | {6, 1},
20 | {7, 2},
21 | {8, 2},
22 | {9, 2},
23 | }
24 | for _, c := range cases {
25 | pool := newTesterAccountPool(t, int(c.Network))
26 | vals := pool.ValidatorSet()
27 | assert.Equal(t, CalcMaxFaultyNodes(vals), int(c.Faulty))
28 | }
29 | }
30 |
31 | // TestNumValid checks if the quorum size is calculated
32 | // correctly based on number of validators (network size).
33 | func TestNumValid(t *testing.T) {
34 | cases := []struct {
35 | Network, Quorum uint64
36 | }{
37 | {1, 1},
38 | {2, 2},
39 | {3, 3},
40 | {4, 3},
41 | {5, 4},
42 | {6, 4},
43 | {7, 5},
44 | {8, 6},
45 | {9, 6},
46 | }
47 |
48 | addAccounts := func(
49 | pool *testerAccountPool,
50 | numAccounts int,
51 | ) {
52 | // add accounts
53 | for i := 0; i < numAccounts; i++ {
54 | pool.add(strconv.Itoa(i))
55 | }
56 | }
57 |
58 | for _, c := range cases {
59 | pool := newTesterAccountPool(t, int(c.Network))
60 | addAccounts(pool, int(c.Network))
61 |
62 | assert.Equal(t,
63 | int(c.Quorum),
64 | OptimalQuorumSize(pool.ValidatorSet()),
65 | )
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/consensus/ibft/transport.go:
--------------------------------------------------------------------------------
1 | package ibft
2 |
3 | import (
4 | "github.com/0xPolygon/go-ibft/messages/proto"
5 | "github.com/ExzoNetwork/ExzoCoin/network"
6 | "github.com/ExzoNetwork/ExzoCoin/types"
7 | "github.com/libp2p/go-libp2p/core/peer"
8 | )
9 |
10 | type transport interface {
11 | Multicast(msg *proto.Message) error
12 | }
13 |
14 | type gossipTransport struct {
15 | topic *network.Topic
16 | }
17 |
18 | func (g *gossipTransport) Multicast(msg *proto.Message) error {
19 | return g.topic.Publish(msg)
20 | }
21 |
22 | func (i *backendIBFT) Multicast(msg *proto.Message) {
23 | if err := i.transport.Multicast(msg); err != nil {
24 | i.logger.Error("fail to gossip", "err", err)
25 | }
26 | }
27 |
28 | // setupTransport sets up the gossip transport protocol
29 | func (i *backendIBFT) setupTransport() error {
30 | // Define a new topic
31 | topic, err := i.network.NewTopic(ibftProto, &proto.Message{})
32 | if err != nil {
33 | return err
34 | }
35 |
36 | // Subscribe to the newly created topic
37 | if err := topic.Subscribe(
38 | func(obj interface{}, _ peer.ID) {
39 | if !i.isActiveValidator() {
40 | return
41 | }
42 |
43 | msg, ok := obj.(*proto.Message)
44 | if !ok {
45 | i.logger.Error("invalid type assertion for message request")
46 |
47 | return
48 | }
49 |
50 | i.consensus.AddMessage(msg)
51 |
52 | i.logger.Debug(
53 | "validator message received",
54 | "type", msg.Type.String(),
55 | "height", msg.GetView().Height,
56 | "round", msg.GetView().Round,
57 | "addr", types.BytesToAddress(msg.From).String(),
58 | )
59 | },
60 | ); err != nil {
61 | return err
62 | }
63 |
64 | i.transport = &gossipTransport{topic: topic}
65 |
66 | return nil
67 | }
68 |
--------------------------------------------------------------------------------
/consensus/ibft/validators.go:
--------------------------------------------------------------------------------
1 | package ibft
2 |
3 | import (
4 | "math"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/types"
7 | "github.com/ExzoNetwork/ExzoCoin/validators"
8 | )
9 |
10 | func CalcMaxFaultyNodes(s validators.Validators) int {
11 | // N -> number of nodes in IBFT
12 | // F -> number of faulty nodes
13 | //
14 | // N = 3F + 1
15 | // => F = (N - 1) / 3
16 | //
17 | // IBFT tolerates 1 failure with 4 nodes
18 | // 4 = 3 * 1 + 1
19 | // To tolerate 2 failures, IBFT requires 7 nodes
20 | // 7 = 3 * 2 + 1
21 | // It should always take the floor of the result
22 | return (s.Len() - 1) / 3
23 | }
24 |
25 | type QuorumImplementation func(validators.Validators) int
26 |
27 | // LegacyQuorumSize returns the legacy quorum size for the given validator set
28 | func LegacyQuorumSize(set validators.Validators) int {
29 | // According to the IBFT spec, the number of valid messages
30 | // needs to be 2F + 1
31 | return 2*CalcMaxFaultyNodes(set) + 1
32 | }
33 |
34 | // OptimalQuorumSize returns the optimal quorum size for the given validator set
35 | func OptimalQuorumSize(set validators.Validators) int {
36 | // if the number of validators is less than 4,
37 | // then the entire set is required
38 | if CalcMaxFaultyNodes(set) == 0 {
39 | /*
40 | N: 1 -> Q: 1
41 | N: 2 -> Q: 2
42 | N: 3 -> Q: 3
43 | */
44 | return set.Len()
45 | }
46 |
47 | // (quorum optimal) Q = ceil(2/3 * N)
48 | return int(math.Ceil(2 * float64(set.Len()) / 3))
49 | }
50 |
51 | func CalcProposer(
52 | validators validators.Validators,
53 | round uint64,
54 | lastProposer types.Address,
55 | ) validators.Validator {
56 | var seed uint64
57 |
58 | if lastProposer == types.ZeroAddress {
59 | seed = round
60 | } else {
61 | offset := int64(0)
62 |
63 | if index := validators.Index(lastProposer); index != -1 {
64 | offset = index
65 | }
66 |
67 | seed = uint64(offset) + round + 1
68 | }
69 |
70 | pick := seed % uint64(validators.Len())
71 |
72 | return validators.At(pick)
73 | }
74 |
--------------------------------------------------------------------------------
/consensus/utils.go:
--------------------------------------------------------------------------------
1 | package consensus
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/types"
5 | "github.com/ExzoNetwork/ExzoCoin/types/buildroot"
6 | )
7 |
8 | // BuildBlockParams are parameters passed into the BuildBlock helper method
9 | type BuildBlockParams struct {
10 | Header *types.Header
11 | Txns []*types.Transaction
12 | Receipts []*types.Receipt
13 | }
14 |
15 | // BuildBlock is a utility function that builds a block, based on the passed in header, transactions and receipts
16 | func BuildBlock(params BuildBlockParams) *types.Block {
17 | txs := params.Txns
18 | header := params.Header
19 |
20 | if len(txs) == 0 {
21 | header.TxRoot = types.EmptyRootHash
22 | } else {
23 | header.TxRoot = buildroot.CalculateTransactionsRoot(txs)
24 | }
25 |
26 | if len(params.Receipts) == 0 {
27 | header.ReceiptsRoot = types.EmptyRootHash
28 | } else {
29 | header.ReceiptsRoot = buildroot.CalculateReceiptsRoot(params.Receipts)
30 | }
31 |
32 | // TODO: Compute uncles
33 | header.Sha3Uncles = types.EmptyUncleHash
34 | header.ComputeHash()
35 |
36 | return &types.Block{
37 | Header: header,
38 | Transactions: txs,
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/contracts/abis/abis.go:
--------------------------------------------------------------------------------
1 | package abis
2 |
3 | import (
4 | "github.com/umbracle/ethgo/abi"
5 | )
6 |
7 | var (
8 | // ABI for Staking Contract
9 | StakingABI = abi.MustNewABI(StakingJSONABI)
10 |
11 | // ABI for Contract used in e2e stress test
12 | StressTestABI = abi.MustNewABI(StressTestJSONABI)
13 | )
14 |
--------------------------------------------------------------------------------
/docker/local/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM golang:1.18-alpine AS builder
2 |
3 | WORKDIR /exzocoin
4 |
5 | ADD go.mod go.sum ./
6 | RUN go mod download
7 |
8 | COPY . .
9 |
10 | RUN go build -o exzocoin main.go
11 |
12 | FROM alpine:latest AS runner
13 |
14 | RUN apk --no-cache add ca-certificates jq
15 |
16 | WORKDIR /exzocoin
17 |
18 | COPY --from=builder /exzocoin/exzocoin ./
19 | COPY ./docker/local/exzocoin.sh ./
20 |
21 | # Expose json-rpc, libp2p and grpc ports
22 | EXPOSE 8545 9632 1478 5001
23 |
24 | ENTRYPOINT ["./exzocoin.sh"]
25 |
--------------------------------------------------------------------------------
/docker/local/exzocoin.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 |
5 | POLYGON_EDGE_BIN=./exzocoin
6 | GENESIS_PATH=/genesis/genesis.json
7 |
8 | case "$1" in
9 |
10 | "init")
11 | if [ -f "$GENESIS_PATH" ]; then
12 | echo "Secrets have already been generated."
13 | else
14 | echo "Generating secrets..."
15 | secrets=$("$POLYGON_EDGE_BIN" secrets init --num 4 --data-dir data- --json)
16 | echo "Secrets have been successfully generated"
17 |
18 | echo "Generating genesis file..."
19 | "$POLYGON_EDGE_BIN" genesis \
20 | --dir "$GENESIS_PATH" \
21 | --consensus ibft \
22 | --ibft-validators-prefix-path data- \
23 | --bootnode /dns4/node-1/tcp/1478/p2p/$(echo $secrets | jq -r '.[0] | .node_id') \
24 | --bootnode /dns4/node-2/tcp/1478/p2p/$(echo $secrets | jq -r '.[1] | .node_id')
25 | echo "Genesis file has been successfully generated"
26 | fi
27 | ;;
28 |
29 | *)
30 | until [ -f "$GENESIS_PATH" ]
31 | do
32 | echo "Waiting 1s for genesis file $GENESIS_PATH to be created by init container..."
33 | sleep 1
34 | done
35 | echo "Executing exzocoin..."
36 | exec "$POLYGON_EDGE_BIN" "$@"
37 | ;;
38 |
39 | esac
40 |
--------------------------------------------------------------------------------
/e2e/README.md:
--------------------------------------------------------------------------------
1 | # E2E tests
2 |
3 | The implemented E2E tests start a local instance of exzocoin.
4 |
5 | ## Step 1: Run the tests
6 |
7 | Use the make file to launch the tests `make test-e2e`
8 |
9 | ## Manual checks if things are acting funny
10 |
11 | ### Check if the exzocoin process is running
12 |
13 | If you've stopped the tests abruptly, chances are the exzocoin process is still running on your machine.
14 | In order for the tests to function normally, please kill the possible remaining processes using `killall exzocoin`
15 |
16 | ### Clean the golang test cache
17 |
18 | Golang caches test results, and may not even run a test, causing tests to fail on some machines and work on others.
19 | ````bash
20 | go clean -testcache
21 | ````
22 |
23 | This command cleans the test cache, and should be added to the runtime config.
24 |
25 | Another way to disable test caching altogether is to add the following flag when running go test `-count=1`:
26 | ````bash
27 | go test ./... -count=1
28 | ````
29 |
30 | ## Note
31 |
32 | ### constants
33 |
34 | Constant values that used in some e2e tests are defined in `e2e/const.go`.
35 | Mock contract are pre-compiled and the result is stored in `const.go` in order to avoid dependencies of solc command (solidity compiler).
36 |
37 | You can get the byte code from original program by following command.
38 |
39 | ```shell
40 | $ solc --bin e2e/sample.sol
41 | ```
42 |
43 | Currently you need to build with version 0.5.x compiler. You can check the compiler version by `solc --version`.
44 |
45 | ```shell
46 | $ solc --version
47 | solc, the solidity compiler commandline interface
48 | Version: 0.5.17+commit.d19bba13.Darwin.appleclang
49 | ```
50 |
--------------------------------------------------------------------------------
/e2e/metadata/StressTest.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.8.0;
2 |
3 | contract StressTest {
4 | string private name;
5 | uint256 private num;
6 |
7 | constructor (){
8 | num = 0;
9 | }
10 |
11 | event txnDone(uint number);
12 |
13 | function setName(string memory sName) external {
14 | num++;
15 | name = sName;
16 | emit txnDone(num);
17 | }
18 |
19 | function getCount() view external returns (uint){
20 | return num;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/e2e/metadata/sample.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.5;
2 | pragma experimental ABIEncoderV2;
3 |
4 | contract Sample {
5 | event A(address indexed val_0, address indexed val_1);
6 |
7 | function setterA(address val_0, address val_1) public payable {
8 | emit A(val_0, val_1);
9 | }
10 |
11 | function setA1() public payable {
12 | emit A(
13 | 0x0000000000000000000000000000000000000000,
14 | 0x0100000000000000000000000000000000000000
15 | );
16 | }
17 |
18 | function setA2() public payable {
19 | emit A(
20 | 0x0100000000000000000000000000000000000000,
21 | 0x0000000000000000000000000000000000000000
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/e2e/syncer_test.go:
--------------------------------------------------------------------------------
1 | package e2e
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "testing"
7 | "time"
8 |
9 | "github.com/ExzoNetwork/ExzoCoin/e2e/framework"
10 | "github.com/ExzoNetwork/ExzoCoin/validators"
11 | )
12 |
13 | func TestClusterBlockSync(t *testing.T) {
14 | const (
15 | numNonValidators = 2
16 | desiredHeight = 10
17 | )
18 |
19 | runTest := func(t *testing.T, validatorType validators.ValidatorType) {
20 | t.Helper()
21 |
22 | // Start IBFT cluster (4 Validator + 2 Non-Validator)
23 | ibftManager := framework.NewIBFTServersManager(
24 | t,
25 | IBFTMinNodes+numNonValidators,
26 | IBFTDirPrefix, func(i int, config *framework.TestServerConfig) {
27 | config.SetValidatorType(validatorType)
28 |
29 | if i >= IBFTMinNodes {
30 | // Other nodes should not be in the validator set
31 | dirPrefix := "exzocoin-non-validator-"
32 | config.SetIBFTDirPrefix(dirPrefix)
33 | config.SetIBFTDir(fmt.Sprintf("%s%d", dirPrefix, i))
34 | }
35 | })
36 |
37 | startContext, startCancelFn := context.WithTimeout(context.Background(), time.Minute)
38 | defer startCancelFn()
39 | ibftManager.StartServers(startContext)
40 |
41 | servers := make([]*framework.TestServer, 0)
42 | for i := 0; i < IBFTMinNodes+numNonValidators; i++ {
43 | servers = append(servers, ibftManager.GetServer(i))
44 | }
45 | // All nodes should have mined the same block eventually
46 | waitErrors := framework.WaitForServersToSeal(servers, desiredHeight)
47 |
48 | if len(waitErrors) != 0 {
49 | t.Fatalf("Unable to wait for all nodes to seal blocks, %v", waitErrors)
50 | }
51 | }
52 |
53 | t.Run("ECDSA", func(t *testing.T) {
54 | runTest(t, validators.ECDSAValidatorType)
55 | })
56 |
57 | t.Run("BLS", func(t *testing.T) {
58 | runTest(t, validators.BLSValidatorType)
59 | })
60 | }
61 |
--------------------------------------------------------------------------------
/helper/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/chain"
5 | "github.com/ExzoNetwork/ExzoCoin/types"
6 | )
7 |
8 | // GetWhitelist fetches whitelist object from the config
9 | func GetWhitelist(config *chain.Chain) *chain.Whitelists {
10 | return config.Params.Whitelists
11 | }
12 |
13 | // GetDeploymentWhitelist fetches deployment whitelist from the genesis config
14 | // if doesn't exist returns empty list
15 | func GetDeploymentWhitelist(genesisConfig *chain.Chain) ([]types.Address, error) {
16 | // Fetch whitelist config if exists, if not init
17 | whitelistConfig := GetWhitelist(genesisConfig)
18 |
19 | // Extract deployment whitelist if exists, if not init
20 | if whitelistConfig == nil {
21 | return make([]types.Address, 0), nil
22 | }
23 |
24 | return whitelistConfig.Deployment, nil
25 | }
26 |
--------------------------------------------------------------------------------
/helper/enode/enode_test.go:
--------------------------------------------------------------------------------
1 | package enode
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 | )
7 |
8 | func TestParseEnode(t *testing.T) {
9 | id1 := "1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"
10 |
11 | enode := func(prefix, id, ip, port string) string {
12 | return fmt.Sprintf("%s://%s@%s:%s", prefix, id, ip, port)
13 | }
14 |
15 | cases := []struct {
16 | Name string
17 | enode string
18 | err bool
19 | }{
20 | {
21 | Name: "Incorrect scheme",
22 | enode: "foo://1234",
23 | err: true,
24 | },
25 | {
26 | Name: "Incorrect IP",
27 | enode: enode("enode", id1, "abc", "30303"),
28 | err: true,
29 | },
30 | {
31 | Name: "IP too long",
32 | enode: enode("enode", id1, "127.0.0.1.1", "30303"),
33 | err: true,
34 | },
35 | {
36 | Name: "IP too short",
37 | enode: enode("enode", id1, "127.0.0", "30303"),
38 | err: true,
39 | },
40 | {
41 | Name: "ID with 0x prefix",
42 | enode: enode("enode", "0x"+id1, "127.0.0.1.1", "30303"),
43 | err: true,
44 | },
45 | {
46 | Name: "ID is not hex",
47 | enode: enode("enode", "abcd", "127.0.0.1", "30303"),
48 | err: true,
49 | },
50 | {
51 | Name: "ID incorrect size",
52 | enode: enode("enode", id1[0:10], "127.0.0.1", "30303"),
53 | err: true,
54 | },
55 | {
56 | Name: "Port is not a number",
57 | enode: enode("enode", id1, "127.0.0.1", "aa"),
58 | err: true,
59 | },
60 | {
61 | Name: "Valid enode",
62 | enode: enode("enode", id1, "127.0.0.1", "30303"),
63 | },
64 | }
65 |
66 | for _, c := range cases {
67 | t.Run(c.Name, func(t *testing.T) {
68 | node, err := ParseURL(c.enode)
69 | if c.err && err == nil {
70 | t.Fatal("expected error")
71 | } else if !c.err && err != nil {
72 | t.Fatal("error not expected")
73 | }
74 |
75 | if err == nil {
76 | if node.String() != c.enode {
77 | t.Fatalf("bad")
78 | }
79 | }
80 | })
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/helper/hex/hex_test.go:
--------------------------------------------------------------------------------
1 | package hex
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | // TestDecodeUint64 verifies that uint64 values
11 | // are properly decoded from hex
12 | func TestDecodeUint64(t *testing.T) {
13 | t.Parallel()
14 |
15 | uint64Array := []uint64{
16 | 0,
17 | 1,
18 | 11,
19 | 67312,
20 | 80604,
21 | ^uint64(0), // max uint64
22 | }
23 |
24 | toHexArr := func(nums []uint64) []string {
25 | numbers := make([]string, len(nums))
26 |
27 | for index, num := range nums {
28 | numbers[index] = fmt.Sprintf("0x%x", num)
29 | }
30 |
31 | return numbers
32 | }
33 |
34 | for index, value := range toHexArr(uint64Array) {
35 | decodedValue, err := DecodeUint64(value)
36 | assert.NoError(t, err)
37 |
38 | assert.Equal(t, uint64Array[index], decodedValue)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/helper/ipc/ipc_unix.go:
--------------------------------------------------------------------------------
1 | //go:build !windows
2 | // +build !windows
3 |
4 | package ipc
5 |
6 | import (
7 | "net"
8 | "os"
9 | "path/filepath"
10 | "time"
11 | )
12 |
13 | // Dial dials an IPC path
14 | func Dial(path string) (net.Conn, error) {
15 | return net.Dial("unix", path)
16 | }
17 |
18 | // DialTimeout dials an IPC path with timeout
19 | func DialTimeout(path string, timeout time.Duration) (net.Conn, error) {
20 | return net.DialTimeout("unix", path, timeout)
21 | }
22 |
23 | // Listen listens an IPC path
24 | func Listen(path string) (net.Listener, error) {
25 | if err := os.MkdirAll(filepath.Dir(path), 0751); err != nil {
26 | return nil, err
27 | }
28 |
29 | if removeErr := os.Remove(path); removeErr != nil {
30 | return nil, removeErr
31 | }
32 |
33 | lis, err := net.Listen("unix", path)
34 | if err != nil {
35 | return nil, err
36 | }
37 |
38 | if chmodErr := os.Chmod(path, 0600); chmodErr != nil {
39 | return nil, chmodErr
40 | }
41 |
42 | return lis, nil
43 | }
44 |
--------------------------------------------------------------------------------
/helper/ipc/ipc_windows.go:
--------------------------------------------------------------------------------
1 | //go:build windows
2 | // +build windows
3 |
4 | package ipc
5 |
6 | import (
7 | "net"
8 | "time"
9 |
10 | "gopkg.in/natefinch/npipe.v2"
11 | )
12 |
13 | // Dial dials an IPC path
14 | func Dial(path string) (net.Conn, error) {
15 | return npipe.Dial(path)
16 | }
17 |
18 | // DialTimeout dials an IPC path with timeout
19 | func DialTimeout(path string, timeout time.Duration) (net.Conn, error) {
20 | return npipe.DialTimeout(path, timeout)
21 | }
22 |
23 | // Listen listens an IPC path
24 | func Listen(path string) (net.Listener, error) {
25 | return npipe.Listen(path)
26 | }
27 |
--------------------------------------------------------------------------------
/helper/keccak/keccak.go:
--------------------------------------------------------------------------------
1 | package keccak
2 |
3 | import (
4 | "hash"
5 |
6 | "github.com/umbracle/fastrlp"
7 | "golang.org/x/crypto/sha3"
8 | )
9 |
10 | type hashImpl interface {
11 | hash.Hash
12 | Read(b []byte) (int, error)
13 | }
14 |
15 | // Keccak is the sha256 keccak hash
16 | type Keccak struct {
17 | buf []byte // buffer to store intermediate rlp marshal values
18 | tmp []byte
19 | hash hashImpl
20 | }
21 |
22 | // WriteRlp writes an RLP value
23 | func (k *Keccak) WriteRlp(dst []byte, v *fastrlp.Value) []byte {
24 | k.buf = v.MarshalTo(k.buf[:0])
25 | k.Write(k.buf)
26 |
27 | return k.Sum(dst)
28 | }
29 |
30 | // Write implements the hash interface
31 | func (k *Keccak) Write(b []byte) (int, error) {
32 | return k.hash.Write(b)
33 | }
34 |
35 | // Reset implements the hash interface
36 | func (k *Keccak) Reset() {
37 | k.buf = k.buf[:0]
38 | k.hash.Reset()
39 | }
40 |
41 | // Read hashes the content and returns the intermediate buffer.
42 | func (k *Keccak) Read() []byte {
43 | k.hash.Read(k.tmp)
44 |
45 | return k.tmp
46 | }
47 |
48 | // Sum implements the hash interface
49 | func (k *Keccak) Sum(dst []byte) []byte {
50 | k.hash.Read(k.tmp)
51 | dst = append(dst, k.tmp[:]...)
52 |
53 | return dst
54 | }
55 |
56 | func newKeccak(hash hashImpl) *Keccak {
57 | return &Keccak{
58 | hash: hash,
59 | tmp: make([]byte, hash.Size()),
60 | }
61 | }
62 |
63 | // NewKeccak256 returns a new keccak 256
64 | func NewKeccak256() *Keccak {
65 | impl, ok := sha3.NewLegacyKeccak256().(hashImpl)
66 | if !ok {
67 | return nil
68 | }
69 |
70 | return newKeccak(impl)
71 | }
72 |
--------------------------------------------------------------------------------
/helper/keccak/keccak_test.go:
--------------------------------------------------------------------------------
1 | package keccak
2 |
--------------------------------------------------------------------------------
/helper/keccak/pool.go:
--------------------------------------------------------------------------------
1 | package keccak
2 |
3 | import (
4 | "sync"
5 |
6 | "github.com/umbracle/fastrlp"
7 | )
8 |
9 | // DefaultKeccakPool is a default pool
10 | var DefaultKeccakPool Pool
11 |
12 | // Pool is a pool of keccaks
13 | type Pool struct {
14 | pool sync.Pool
15 | }
16 |
17 | // Get returns the keccak
18 | func (p *Pool) Get() *Keccak {
19 | v := p.pool.Get()
20 | if v == nil {
21 | return NewKeccak256()
22 | }
23 |
24 | keccakVal, ok := v.(*Keccak)
25 | if !ok {
26 | return nil
27 | }
28 |
29 | return keccakVal
30 | }
31 |
32 | // Put releases the keccak
33 | func (p *Pool) Put(k *Keccak) {
34 | k.Reset()
35 | p.pool.Put(k)
36 | }
37 |
38 | // Keccak256 hashes a src with keccak-256
39 | func Keccak256(dst, src []byte) []byte {
40 | h := DefaultKeccakPool.Get()
41 | h.Write(src)
42 | dst = h.Sum(dst)
43 | DefaultKeccakPool.Put(h)
44 |
45 | return dst
46 | }
47 |
48 | // Keccak256Rlp hashes a fastrlp.Value with keccak-256
49 | func Keccak256Rlp(dst []byte, src *fastrlp.Value) []byte {
50 | h := DefaultKeccakPool.Get()
51 | dst = h.WriteRlp(dst, src)
52 | DefaultKeccakPool.Put(h)
53 |
54 | return dst
55 | }
56 |
--------------------------------------------------------------------------------
/helper/keystore/keystore.go:
--------------------------------------------------------------------------------
1 | package keystore
2 |
3 | import (
4 | "encoding/hex"
5 | "fmt"
6 | "os"
7 | )
8 |
9 | type createFn func() ([]byte, error)
10 |
11 | // CreateIfNotExists generates a private key at the specified path,
12 | // or reads the file on that path if it is present
13 | func CreateIfNotExists(path string, create createFn) ([]byte, error) {
14 | _, err := os.Stat(path)
15 | if err != nil && !os.IsNotExist(err) {
16 | return nil, fmt.Errorf("failed to stat (%s): %w", path, err)
17 | }
18 |
19 | var keyBuff []byte
20 | if !os.IsNotExist(err) {
21 | // Key exists
22 | keyBuff, err = os.ReadFile(path)
23 | if err != nil {
24 | return nil, fmt.Errorf("unable to read private key from disk (%s), %w", path, err)
25 | }
26 |
27 | return keyBuff, nil
28 | }
29 |
30 | // Key doesn't exist yet, generate it
31 | keyBuff, err = create()
32 | if err != nil {
33 | return nil, fmt.Errorf("unable to generate private key, %w", err)
34 | }
35 |
36 | // Encode it to a readable format (Base64) and write to disk
37 | keyBuff = []byte(hex.EncodeToString(keyBuff))
38 | if err = os.WriteFile(path, keyBuff, os.ModePerm); err != nil {
39 | return nil, fmt.Errorf("unable to write private key to disk (%s), %w", path, err)
40 | }
41 |
42 | return keyBuff, nil
43 | }
44 |
45 | func CreatePrivateKey(create createFn) ([]byte, error) {
46 | keyBuff, err := create()
47 | if err != nil {
48 | return nil, fmt.Errorf("unable to generate private key, %w", err)
49 | }
50 |
51 | // Encode it to a readable format (Base64) and return
52 | return []byte(hex.EncodeToString(keyBuff)), nil
53 | }
54 |
--------------------------------------------------------------------------------
/helper/tests/assert.go:
--------------------------------------------------------------------------------
1 | package tests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/assert"
7 | )
8 |
9 | // AssertErrorMessageContains is a helper function to make sure
10 | // an error message matches with the expected error which is not exported
11 | // if expected error is nil, it checks the target error is nil
12 | func AssertErrorMessageContains(t *testing.T, expected, target error) {
13 | t.Helper()
14 |
15 | if expected != nil {
16 | assert.ErrorContains(t, target, expected.Error())
17 | } else {
18 | assert.NoError(t, target)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/jsonrpc/eth_txpool_test.go:
--------------------------------------------------------------------------------
1 | package jsonrpc
2 |
3 | import (
4 | "math/big"
5 | "testing"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/types"
8 | "github.com/stretchr/testify/assert"
9 | )
10 |
11 | func TestEth_TxnPool_SendRawTransaction(t *testing.T) {
12 | store := &mockStoreTxn{}
13 | eth := newTestEthEndpoint(store)
14 |
15 | txn := &types.Transaction{
16 | From: addr0,
17 | V: big.NewInt(1),
18 | }
19 | txn.ComputeHash()
20 |
21 | data := txn.MarshalRLP()
22 | _, err := eth.SendRawTransaction(data)
23 | assert.NoError(t, err)
24 | assert.NotEqual(t, store.txn.Hash, types.ZeroHash)
25 |
26 | // the hash in the txn pool should match the one we send
27 | if txn.Hash != store.txn.Hash {
28 | t.Fatal("bad")
29 | }
30 | }
31 |
32 | func TestEth_TxnPool_SendTransaction(t *testing.T) {
33 | store := &mockStoreTxn{}
34 | store.AddAccount(addr0)
35 | eth := newTestEthEndpoint(store)
36 |
37 | txToSend := &types.Transaction{
38 | From: addr0,
39 | To: argAddrPtr(addr0),
40 | Nonce: uint64(0),
41 | GasPrice: big.NewInt(int64(1)),
42 | }
43 |
44 | _, err := eth.SendRawTransaction(txToSend.MarshalRLP())
45 | assert.NoError(t, err)
46 | assert.NotEqual(t, store.txn.Hash, types.ZeroHash)
47 | }
48 |
49 | type mockStoreTxn struct {
50 | ethStore
51 | accounts map[types.Address]*mockAccount
52 | txn *types.Transaction
53 | }
54 |
55 | func (m *mockStoreTxn) AddTx(tx *types.Transaction) error {
56 | m.txn = tx
57 |
58 | return nil
59 | }
60 |
61 | func (m *mockStoreTxn) GetNonce(addr types.Address) uint64 {
62 | return 1
63 | }
64 |
65 | func (m *mockStoreTxn) AddAccount(addr types.Address) *mockAccount {
66 | if m.accounts == nil {
67 | m.accounts = map[types.Address]*mockAccount{}
68 | }
69 |
70 | acct := &mockAccount{
71 | address: addr,
72 | account: &Account{},
73 | storage: make(map[types.Hash][]byte),
74 | }
75 | m.accounts[addr] = acct
76 |
77 | return acct
78 | }
79 |
80 | func (m *mockStoreTxn) Header() *types.Header {
81 | return &types.Header{}
82 | }
83 |
84 | func (m *mockStoreTxn) GetAccount(root types.Hash, addr types.Address) (*Account, error) {
85 | acct, ok := m.accounts[addr]
86 | if !ok {
87 | return nil, ErrStateNotFound
88 | }
89 |
90 | return acct.account, nil
91 | }
92 |
--------------------------------------------------------------------------------
/jsonrpc/jsonrpc_test.go:
--------------------------------------------------------------------------------
1 | package jsonrpc
2 |
3 | import (
4 | "bytes"
5 | "encoding/json"
6 | "net"
7 | "testing"
8 |
9 | "github.com/ExzoNetwork/ExzoCoin/helper/tests"
10 | "github.com/ExzoNetwork/ExzoCoin/versioning"
11 | "github.com/stretchr/testify/assert"
12 |
13 | "github.com/hashicorp/go-hclog"
14 | )
15 |
16 | func TestHTTPServer(t *testing.T) {
17 | store := newMockStore()
18 | port, portErr := tests.GetFreePort()
19 |
20 | if portErr != nil {
21 | t.Fatalf("Unable to fetch free port, %v", portErr)
22 | }
23 |
24 | config := &Config{
25 | Store: store,
26 | Addr: &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: port},
27 | }
28 | _, err := NewJSONRPC(hclog.NewNullLogger(), config)
29 |
30 | if err != nil {
31 | t.Fatal(err)
32 | }
33 | }
34 |
35 | func Test_handleGetRequest(t *testing.T) {
36 | var (
37 | chainName = "exzocoin-test"
38 | chainID = uint64(200)
39 | )
40 |
41 | jsonRPC := &JSONRPC{
42 | config: &Config{
43 | ChainName: chainName,
44 | ChainID: chainID,
45 | },
46 | }
47 |
48 | mockWriter := bytes.NewBuffer(nil)
49 |
50 | jsonRPC.handleGetRequest(mockWriter)
51 |
52 | response := &GetResponse{}
53 |
54 | assert.NoError(
55 | t,
56 | json.Unmarshal(mockWriter.Bytes(), response),
57 | )
58 |
59 | assert.Equal(
60 | t,
61 | &GetResponse{
62 | Name: chainName,
63 | ChainID: chainID,
64 | Version: versioning.Version,
65 | },
66 | response,
67 | )
68 | }
69 |
--------------------------------------------------------------------------------
/jsonrpc/net_endpoint.go:
--------------------------------------------------------------------------------
1 | package jsonrpc
2 |
3 | import "strconv"
4 |
5 | // networkStore provides methods needed for Net endpoint
6 | type networkStore interface {
7 | GetPeers() int
8 | }
9 |
10 | // Net is the net jsonrpc endpoint
11 | type Net struct {
12 | store networkStore
13 | chainID uint64
14 | }
15 |
16 | // Version returns the current network id
17 | func (n *Net) Version() (interface{}, error) {
18 | return strconv.FormatUint(n.chainID, 10), nil
19 | }
20 |
21 | // Listening returns true if client is actively listening for network connections
22 | func (n *Net) Listening() (interface{}, error) {
23 | return true, nil
24 | }
25 |
26 | // PeerCount returns number of peers currently connected to the client
27 | func (n *Net) PeerCount() (interface{}, error) {
28 | peers := n.store.GetPeers()
29 |
30 | return argUint64(peers), nil
31 | }
32 |
--------------------------------------------------------------------------------
/jsonrpc/net_endpoint_test.go:
--------------------------------------------------------------------------------
1 | package jsonrpc
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/hashicorp/go-hclog"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestNetEndpoint_PeerCount(t *testing.T) {
11 | dispatcher := newDispatcher(
12 | hclog.NewNullLogger(),
13 | newMockStore(),
14 | &dispatcherParams{
15 | chainID: 1,
16 | })
17 |
18 | resp, err := dispatcher.Handle([]byte(`{
19 | "method": "net_peerCount",
20 | "params": [""]
21 | }`))
22 | assert.NoError(t, err)
23 |
24 | var res string
25 |
26 | assert.NoError(t, expectJSONResult(resp, &res))
27 | assert.Equal(t, "0x14", res)
28 | }
29 |
--------------------------------------------------------------------------------
/jsonrpc/testsuite/block-empty.json:
--------------------------------------------------------------------------------
1 | {
2 | "parentHash": "0x0100000000000000000000000000000000000000000000000000000000000000",
3 | "sha3Uncles": "0x0200000000000000000000000000000000000000000000000000000000000000",
4 | "miner": "0x0100000000000000000000000000000000000000",
5 | "stateRoot": "0x0400000000000000000000000000000000000000000000000000000000000000",
6 | "transactionsRoot": "0x0500000000000000000000000000000000000000000000000000000000000000",
7 | "receiptsRoot": "0x0600000000000000000000000000000000000000000000000000000000000000",
8 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
9 | "difficulty": "0xa",
10 | "totalDifficulty": "0x0",
11 | "size": "0x0",
12 | "number": "0xb",
13 | "gasLimit": "0xc",
14 | "gasUsed": "0xd",
15 | "timestamp": "0xe",
16 | "extraData": "0x616263646566",
17 | "mixHash": "0x0700000000000000000000000000000000000000000000000000000000000000",
18 | "nonce": "0x0a00000000000000",
19 | "hash": "0x0800000000000000000000000000000000000000000000000000000000000000",
20 | "transactions": null,
21 | "uncles": null
22 | }
--------------------------------------------------------------------------------
/jsonrpc/testsuite/block-with-txn-bodies.json:
--------------------------------------------------------------------------------
1 | {
2 | "parentHash": "0x0100000000000000000000000000000000000000000000000000000000000000",
3 | "sha3Uncles": "0x0200000000000000000000000000000000000000000000000000000000000000",
4 | "miner": "0x0100000000000000000000000000000000000000",
5 | "stateRoot": "0x0400000000000000000000000000000000000000000000000000000000000000",
6 | "transactionsRoot": "0x0500000000000000000000000000000000000000000000000000000000000000",
7 | "receiptsRoot": "0x0600000000000000000000000000000000000000000000000000000000000000",
8 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
9 | "difficulty": "0xa",
10 | "totalDifficulty": "0x0",
11 | "size": "0x0",
12 | "number": "0xb",
13 | "gasLimit": "0xc",
14 | "gasUsed": "0xd",
15 | "timestamp": "0xe",
16 | "extraData": "0x616263646566",
17 | "mixHash": "0x0700000000000000000000000000000000000000000000000000000000000000",
18 | "nonce": "0x0a00000000000000",
19 | "hash": "0x0800000000000000000000000000000000000000000000000000000000000000",
20 | "transactions": [
21 | {
22 | "nonce": "0x1",
23 | "gasPrice": "0xa",
24 | "gas": "0x64",
25 | "to": "0x0000000000000000000000000000000000000000",
26 | "value": "0x3e8",
27 | "input": "0x0102",
28 | "v": "0x1",
29 | "r": "0x2",
30 | "s": "0x3",
31 | "hash": "0x0200000000000000000000000000000000000000000000000000000000000000",
32 | "from": "0x0300000000000000000000000000000000000000",
33 | "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
34 | "blockNumber": "0x1",
35 | "transactionIndex": "0x2"
36 | }
37 | ],
38 | "uncles": null
39 | }
--------------------------------------------------------------------------------
/jsonrpc/testsuite/block-with-txn-hashes.json:
--------------------------------------------------------------------------------
1 | {
2 | "parentHash": "0x0100000000000000000000000000000000000000000000000000000000000000",
3 | "sha3Uncles": "0x0200000000000000000000000000000000000000000000000000000000000000",
4 | "miner": "0x0100000000000000000000000000000000000000",
5 | "stateRoot": "0x0400000000000000000000000000000000000000000000000000000000000000",
6 | "transactionsRoot": "0x0500000000000000000000000000000000000000000000000000000000000000",
7 | "receiptsRoot": "0x0600000000000000000000000000000000000000000000000000000000000000",
8 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
9 | "difficulty": "0xa",
10 | "totalDifficulty": "0x0",
11 | "size": "0x0",
12 | "number": "0xb",
13 | "gasLimit": "0xc",
14 | "gasUsed": "0xd",
15 | "timestamp": "0xe",
16 | "extraData": "0x616263646566",
17 | "mixHash": "0x0700000000000000000000000000000000000000000000000000000000000000",
18 | "nonce": "0x0a00000000000000",
19 | "hash": "0x0800000000000000000000000000000000000000000000000000000000000000",
20 | "transactions": [
21 | "0x0800000000000000000000000000000000000000000000000000000000000000"
22 | ],
23 | "uncles": null
24 | }
--------------------------------------------------------------------------------
/jsonrpc/testsuite/transaction-pending.json:
--------------------------------------------------------------------------------
1 | {
2 | "nonce": "0x1",
3 | "gasPrice": "0xa",
4 | "gas": "0x64",
5 | "to": "0x0000000000000000000000000000000000000000",
6 | "value": "0x3e8",
7 | "input": "0x0102",
8 | "v": "0x1",
9 | "r": "0x2",
10 | "s": "0x3",
11 | "hash": "0x0200000000000000000000000000000000000000000000000000000000000000",
12 | "from": "0x0300000000000000000000000000000000000000",
13 | "blockHash": null,
14 | "blockNumber": null,
15 | "transactionIndex": null
16 | }
--------------------------------------------------------------------------------
/jsonrpc/testsuite/transaction-sealed.json:
--------------------------------------------------------------------------------
1 | {
2 | "nonce": "0x1",
3 | "gasPrice": "0xa",
4 | "gas": "0x64",
5 | "to": "0x0000000000000000000000000000000000000000",
6 | "value": "0x3e8",
7 | "input": "0x0102",
8 | "v": "0x1",
9 | "r": "0x2",
10 | "s": "0x3",
11 | "hash": "0x0200000000000000000000000000000000000000000000000000000000000000",
12 | "from": "0x0300000000000000000000000000000000000000",
13 | "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
14 | "blockNumber": "0x1",
15 | "transactionIndex": "0x2"
16 | }
--------------------------------------------------------------------------------
/jsonrpc/web3_endpoint.go:
--------------------------------------------------------------------------------
1 | package jsonrpc
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/helper/keccak"
7 | "github.com/ExzoNetwork/ExzoCoin/versioning"
8 | )
9 |
10 | // Web3 is the web3 jsonrpc endpoint
11 | type Web3 struct {
12 | chainID uint64
13 | chainName string
14 | }
15 |
16 | var clientVersionTemplate = "%s [chain-id: %d] [version: %s]"
17 |
18 | // ClientVersion returns the version of the web3 client (web3_clientVersion)
19 | func (w *Web3) ClientVersion() (interface{}, error) {
20 | return fmt.Sprintf(
21 | clientVersionTemplate,
22 | w.chainName,
23 | w.chainID,
24 | versioning.Version,
25 | ), nil
26 | }
27 |
28 | // Sha3 returns Keccak-256 (not the standardized SHA3-256) of the given data
29 | func (w *Web3) Sha3(v argBytes) (interface{}, error) {
30 | dst := keccak.Keccak256(nil, v)
31 |
32 | return argBytes(dst), nil
33 | }
34 |
--------------------------------------------------------------------------------
/jsonrpc/web3_endpoint_test.go:
--------------------------------------------------------------------------------
1 | package jsonrpc
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/versioning"
8 |
9 | "github.com/hashicorp/go-hclog"
10 | "github.com/stretchr/testify/assert"
11 | )
12 |
13 | func TestWeb3EndpointSha3(t *testing.T) {
14 | dispatcher := newDispatcher(
15 | hclog.NewNullLogger(),
16 | newMockStore(),
17 | &dispatcherParams{
18 | chainID: 0,
19 | priceLimit: 0,
20 | jsonRPCBatchLengthLimit: 20,
21 | blockRangeLimit: 1000,
22 | })
23 |
24 | resp, err := dispatcher.Handle([]byte(`{
25 | "method": "web3_sha3",
26 | "params": ["0x68656c6c6f20776f726c64"]
27 | }`))
28 | assert.NoError(t, err)
29 |
30 | var res string
31 |
32 | assert.NoError(t, expectJSONResult(resp, &res))
33 | assert.Equal(t, "0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad", res)
34 | }
35 |
36 | func TestWeb3EndpointClientVersion(t *testing.T) {
37 | var (
38 | chainName = "test-chain"
39 | chainID = uint64(100)
40 | )
41 |
42 | dispatcher := newDispatcher(
43 | hclog.NewNullLogger(),
44 | newMockStore(),
45 | &dispatcherParams{
46 | chainID: chainID,
47 | chainName: chainName,
48 | priceLimit: 0,
49 | jsonRPCBatchLengthLimit: 20,
50 | blockRangeLimit: 1000,
51 | },
52 | )
53 |
54 | resp, err := dispatcher.Handle([]byte(`{
55 | "method": "web3_clientVersion",
56 | "params": []
57 | }`))
58 | assert.NoError(t, err)
59 |
60 | var res string
61 |
62 | assert.NoError(t, expectJSONResult(resp, &res))
63 | assert.Contains(t, res,
64 | fmt.Sprintf(
65 | clientVersionTemplate,
66 | chainName,
67 | chainID,
68 | versioning.Version,
69 | ),
70 | )
71 | }
72 |
--------------------------------------------------------------------------------
/licenses/licenses.go:
--------------------------------------------------------------------------------
1 | package licenses
2 |
3 | import (
4 | _ "embed"
5 |
6 | "encoding/json"
7 | )
8 |
9 | type DepLicense struct {
10 | Name string `json:"name"`
11 | Version *string `json:"version"`
12 | Type string `json:"type"`
13 | Path string `json:"path"`
14 | }
15 |
16 | var (
17 | // Polygon Edge License
18 | License string
19 |
20 | // Dependency Licenses
21 | //go:embed bsd_licenses.json
22 | bsdLicensesJSON string
23 | bsdLicenses []DepLicense
24 | )
25 |
26 | func SetLicense(license string) {
27 | License = license
28 | }
29 |
30 | func GetBSDLicenses() ([]DepLicense, error) {
31 | if bsdLicenses == nil {
32 | if err := json.Unmarshal([]byte(bsdLicensesJSON), &bsdLicenses); err != nil {
33 | return nil, err
34 | }
35 | }
36 |
37 | return bsdLicenses, nil
38 | }
39 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | _ "embed"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/command/root"
7 | "github.com/ExzoNetwork/ExzoCoin/licenses"
8 | )
9 |
10 | var (
11 | //go:embed LICENSE
12 | license string
13 | )
14 |
15 | func main() {
16 | licenses.SetLicense(license)
17 |
18 | root.NewRootCommand().Execute()
19 | }
20 |
--------------------------------------------------------------------------------
/network/bootnodes.go:
--------------------------------------------------------------------------------
1 | package network
2 |
3 | import (
4 | "sync/atomic"
5 |
6 | "github.com/libp2p/go-libp2p/core/peer"
7 | )
8 |
9 | type bootnodesWrapper struct {
10 | // bootnodeArr is the array that contains all the bootnode addresses
11 | bootnodeArr []*peer.AddrInfo
12 |
13 | // bootnodesMap is a map used for quick bootnode lookup
14 | bootnodesMap map[peer.ID]*peer.AddrInfo
15 |
16 | // bootnodeConnCount is an atomic value that keeps track
17 | // of the number of bootnode connections
18 | bootnodeConnCount int64
19 | }
20 |
21 | // isBootnode checks if the node ID belongs to a set bootnode
22 | func (bw *bootnodesWrapper) isBootnode(nodeID peer.ID) bool {
23 | _, ok := bw.bootnodesMap[nodeID]
24 |
25 | return ok
26 | }
27 |
28 | // getBootnodeConnCount loads the bootnode connection count [Thread safe]
29 | func (bw *bootnodesWrapper) getBootnodeConnCount() int64 {
30 | return atomic.LoadInt64(&bw.bootnodeConnCount)
31 | }
32 |
33 | // increaseBootnodeConnCount increases the bootnode connection count by delta [Thread safe]
34 | func (bw *bootnodesWrapper) increaseBootnodeConnCount(delta int64) {
35 | atomic.AddInt64(&bw.bootnodeConnCount, delta)
36 | }
37 |
38 | // getBootnodes gets all the bootnodes
39 | func (bw *bootnodesWrapper) getBootnodes() []*peer.AddrInfo {
40 | return bw.bootnodeArr
41 | }
42 |
43 | // getBootnodeCount returns the number of set bootnodes
44 | func (bw *bootnodesWrapper) getBootnodeCount() int {
45 | return len(bw.bootnodeArr)
46 | }
47 |
48 | // hasBootnodes checks if any bootnodes are set [Thread safe]
49 | func (bw *bootnodesWrapper) hasBootnodes() bool {
50 | return bw.getBootnodeCount() > 0
51 | }
52 |
--------------------------------------------------------------------------------
/network/config.go:
--------------------------------------------------------------------------------
1 | package network
2 |
3 | import (
4 | "net"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/chain"
7 | "github.com/ExzoNetwork/ExzoCoin/secrets"
8 | "github.com/multiformats/go-multiaddr"
9 | )
10 |
11 | // Config details the params for the base networking server
12 | type Config struct {
13 | NoDiscover bool // flag indicating if the discovery mechanism should be turned on
14 | Addr *net.TCPAddr // the base address
15 | NatAddr net.IP // the NAT address
16 | DNS multiaddr.Multiaddr // the DNS address
17 | DataDir string // the base data directory for the client
18 | MaxPeers int64 // the maximum number of peer connections
19 | MaxInboundPeers int64 // the maximum number of inbound peer connections
20 | MaxOutboundPeers int64 // the maximum number of outbound peer connections
21 | Chain *chain.Chain // the reference to the chain configuration
22 | SecretsManager secrets.SecretsManager // the secrets manager used for key storage
23 | }
24 |
25 | func DefaultConfig() *Config {
26 | return &Config{
27 | // The discovery service is turned on by default
28 | NoDiscover: false,
29 | // Addresses are bound to localhost by default
30 | Addr: &net.TCPAddr{
31 | IP: net.ParseIP("127.0.0.1"),
32 | Port: DefaultLibp2pPort,
33 | },
34 | // The default ratio for outbound / max peer connections is 0.20
35 | MaxPeers: 40,
36 | // The default ratio for outbound / inbound connections is 0.25
37 | MaxInboundPeers: 32,
38 | MaxOutboundPeers: 8,
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/network/dial/dial_task.go:
--------------------------------------------------------------------------------
1 | package dial
2 |
3 | import "github.com/libp2p/go-libp2p/core/peer"
4 |
5 | type DialTask struct {
6 | index int
7 |
8 | // info of the task
9 | addrInfo *peer.AddrInfo
10 |
11 | // priority of the task (the higher the better)
12 | priority uint64
13 | }
14 |
15 | // GetAddrInfo returns the peer information associated with the dial
16 | func (dt *DialTask) GetAddrInfo() *peer.AddrInfo {
17 | return dt.addrInfo
18 | }
19 |
--------------------------------------------------------------------------------
/network/dial/heap.go:
--------------------------------------------------------------------------------
1 | package dial
2 |
3 | // The DialQueue is implemented as priority queue which utilizes a heap (standard Go implementation)
4 | // https://golang.org/src/container/heap/heap.go
5 | type dialQueueImpl []*DialTask
6 |
7 | // Len returns the length of the queue
8 | func (t dialQueueImpl) Len() int { return len(t) }
9 |
10 | // Less compares the priorities of two tasks at the passed in indexes (A < B)
11 | func (t dialQueueImpl) Less(i, j int) bool {
12 | return t[i].priority < t[j].priority
13 | }
14 |
15 | // Swap swaps the places of the tasks at the passed-in indexes
16 | func (t dialQueueImpl) Swap(i, j int) {
17 | t[i], t[j] = t[j], t[i]
18 | t[i].index = i
19 | t[j].index = j
20 | }
21 |
22 | // Push adds a new item to the queue
23 | func (t *dialQueueImpl) Push(x interface{}) {
24 | n := len(*t)
25 | item := x.(*DialTask) //nolint:forcetypeassert
26 | item.index = n
27 | *t = append(*t, item)
28 | }
29 |
30 | // Pop removes an item from the queue
31 | func (t *dialQueueImpl) Pop() interface{} {
32 | old := *t
33 | n := len(old)
34 | item := old[n-1]
35 | old[n-1] = nil
36 | item.index = -1
37 | *t = old[0 : n-1]
38 |
39 | return item
40 | }
41 |
--------------------------------------------------------------------------------
/network/event/peer_event.go:
--------------------------------------------------------------------------------
1 | package event
2 |
3 | import "github.com/libp2p/go-libp2p/core/peer"
4 |
5 | type PeerEventType uint
6 |
7 | const (
8 | PeerConnected PeerEventType = iota // Emitted when a peer connected
9 | PeerFailedToConnect // Emitted when a peer failed to connect
10 | PeerDisconnected // Emitted when a peer disconnected from node
11 | PeerDialCompleted // Emitted when a peer completed dial
12 | PeerAddedToDialQueue // Emitted when a peer is added to dial queue
13 | )
14 |
15 | var peerEventToName = map[PeerEventType]string{
16 | PeerConnected: "PeerConnected",
17 | PeerFailedToConnect: "PeerFailedToConnect",
18 | PeerDisconnected: "PeerDisconnected",
19 | PeerDialCompleted: "PeerDialCompleted",
20 | PeerAddedToDialQueue: "PeerAddedToDialQueue",
21 | }
22 |
23 | type PeerEvent struct {
24 | // PeerID is the id of the peer that triggered
25 | // the event
26 | PeerID peer.ID
27 |
28 | // Type is the type of the event
29 | Type PeerEventType
30 | }
31 |
32 | func (s PeerEventType) String() string {
33 | name, ok := peerEventToName[s]
34 | if !ok {
35 | return "unknown"
36 | }
37 |
38 | return name
39 | }
40 |
--------------------------------------------------------------------------------
/network/keystore.go:
--------------------------------------------------------------------------------
1 | package network
2 |
3 | import (
4 | "encoding/hex"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/secrets"
7 | "github.com/libp2p/go-libp2p/core/crypto"
8 | )
9 |
10 | // ReadLibp2pKey reads the private networking key from the secrets manager
11 | func ReadLibp2pKey(manager secrets.SecretsManager) (crypto.PrivKey, error) {
12 | libp2pKey, err := manager.GetSecret(secrets.NetworkKey)
13 | if err != nil {
14 | return nil, err
15 | }
16 |
17 | return ParseLibp2pKey(libp2pKey)
18 | }
19 |
20 | // GenerateAndEncodeLibp2pKey generates a new networking private key, and encodes it into hex
21 | func GenerateAndEncodeLibp2pKey() (crypto.PrivKey, []byte, error) {
22 | priv, _, err := crypto.GenerateKeyPair(crypto.Secp256k1, 256)
23 | if err != nil {
24 | return nil, nil, err
25 | }
26 |
27 | buf, err := crypto.MarshalPrivateKey(priv)
28 | if err != nil {
29 | return nil, nil, err
30 | }
31 |
32 | return priv, []byte(hex.EncodeToString(buf)), nil
33 | }
34 |
35 | // ParseLibp2pKey converts a byte array to a private key
36 | func ParseLibp2pKey(key []byte) (crypto.PrivKey, error) {
37 | buf, err := hex.DecodeString(string(key))
38 | if err != nil {
39 | return nil, err
40 | }
41 |
42 | libp2pKey, err := crypto.UnmarshalPrivateKey(buf)
43 | if err != nil {
44 | return nil, err
45 | }
46 |
47 | return libp2pKey, nil
48 | }
49 |
--------------------------------------------------------------------------------
/network/proto/discovery.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package v1;
4 |
5 | option go_package = "/network/proto";
6 |
7 | service Discovery {
8 | rpc FindPeers(FindPeersReq) returns (FindPeersResp);
9 | }
10 |
11 | message FindPeersReq {
12 | string key = 1;
13 | int64 count = 2;
14 | }
15 |
16 | message FindPeersResp {
17 | repeated string nodes = 1;
18 | }
19 |
--------------------------------------------------------------------------------
/network/proto/identity.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package v1;
4 |
5 | option go_package = "/network/proto";
6 |
7 | service Identity {
8 | rpc Hello(Status) returns (Status);
9 | }
10 |
11 | message Status {
12 | map metadata = 1;
13 |
14 | repeated Key keys = 2;
15 |
16 | int64 chain = 3;
17 |
18 | string genesis = 4;
19 |
20 | bool temporaryDial = 5;
21 |
22 | message Key {
23 | string signature = 1;
24 | string message = 2;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/network/proto/testing.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package v1;
4 |
5 | option go_package = "/network/proto";
6 |
7 | service TestService {
8 | rpc SayHello(GenericMessage) returns (GenericMessage);
9 | rpc GetChattyServer(ChattyRequest) returns (stream GenericMessage);
10 | rpc GetChattyClient(stream GenericMessage) returns (GenericMessage);
11 | rpc GetChattyBidi(stream GenericMessage) returns (stream GenericMessage);
12 | }
13 |
14 | message GenericMessage {
15 | string message = 1;
16 | }
17 |
18 | message ChattyRequest {
19 | string message = 1;
20 | int32 count = 2;
21 | }
--------------------------------------------------------------------------------
/secrets/config.go:
--------------------------------------------------------------------------------
1 | package secrets
2 |
3 | import (
4 | "encoding/json"
5 | "os"
6 | )
7 |
8 | // SecretsManagerConfig is the configuration that gets
9 | // written to a single configuration file
10 | type SecretsManagerConfig struct {
11 | Token string `json:"token"` // Access token to the instance
12 | ServerURL string `json:"server_url"` // The URL of the running server
13 | Type SecretsManagerType `json:"type"` // The type of SecretsManager
14 | Name string `json:"name"` // The name of the current node
15 | Namespace string `json:"namespace"` // The namespace of the service
16 | Extra map[string]interface{} `json:"extra"` // Any kind of arbitrary data
17 | }
18 |
19 | // WriteConfig writes the current configuration to the specified path
20 | func (c *SecretsManagerConfig) WriteConfig(path string) error {
21 | jsonBytes, _ := json.MarshalIndent(c, "", " ")
22 |
23 | return os.WriteFile(path, jsonBytes, os.ModePerm)
24 | }
25 |
26 | // ReadConfig reads the SecretsManagerConfig from the specified path
27 | func ReadConfig(path string) (*SecretsManagerConfig, error) {
28 | configFile, readErr := os.ReadFile(path)
29 | if readErr != nil {
30 | return nil, readErr
31 | }
32 |
33 | config := &SecretsManagerConfig{}
34 |
35 | unmarshalErr := json.Unmarshal(configFile, &config)
36 | if unmarshalErr != nil {
37 | return nil, unmarshalErr
38 | }
39 |
40 | return config, nil
41 | }
42 |
--------------------------------------------------------------------------------
/secrets/secrets_test.go:
--------------------------------------------------------------------------------
1 | package secrets
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/assert"
7 | )
8 |
9 | func TestSupportedServiceManager(t *testing.T) {
10 | testTable := []struct {
11 | name string
12 | serviceName SecretsManagerType
13 | supported bool
14 | }{
15 | {
16 | "Valid local secrets manager",
17 | Local,
18 | true,
19 | },
20 | {
21 | "Valid Hashicorp Vault secrets manager",
22 | HashicorpVault,
23 | true,
24 | },
25 | {
26 | "Valid AWS SSM secrets manager",
27 | AWSSSM,
28 | true,
29 | },
30 | {
31 | "Valid GCP secrets manager",
32 | GCPSSM,
33 | true,
34 | },
35 | {
36 | "Invalid secrets manager",
37 | "MarsSecretsManager",
38 | false,
39 | },
40 | }
41 |
42 | for _, testCase := range testTable {
43 | t.Run(testCase.name, func(t *testing.T) {
44 | assert.Equal(
45 | t,
46 | testCase.supported,
47 | SupportedServiceManager(testCase.serviceName),
48 | )
49 | })
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/server/builtin.go:
--------------------------------------------------------------------------------
1 | package server
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/consensus"
5 | consensusDev "github.com/ExzoNetwork/ExzoCoin/consensus/dev"
6 | consensusDummy "github.com/ExzoNetwork/ExzoCoin/consensus/dummy"
7 | consensusIBFT "github.com/ExzoNetwork/ExzoCoin/consensus/ibft"
8 | "github.com/ExzoNetwork/ExzoCoin/secrets"
9 | "github.com/ExzoNetwork/ExzoCoin/secrets/awsssm"
10 | "github.com/ExzoNetwork/ExzoCoin/secrets/gcpssm"
11 | "github.com/ExzoNetwork/ExzoCoin/secrets/hashicorpvault"
12 | "github.com/ExzoNetwork/ExzoCoin/secrets/local"
13 | )
14 |
15 | type ConsensusType string
16 |
17 | const (
18 | DevConsensus ConsensusType = "dev"
19 | IBFTConsensus ConsensusType = "ibft"
20 | DummyConsensus ConsensusType = "dummy"
21 | )
22 |
23 | var consensusBackends = map[ConsensusType]consensus.Factory{
24 | DevConsensus: consensusDev.Factory,
25 | IBFTConsensus: consensusIBFT.Factory,
26 | DummyConsensus: consensusDummy.Factory,
27 | }
28 |
29 | // secretsManagerBackends defines the SecretManager factories for different
30 | // secret management solutions
31 | var secretsManagerBackends = map[secrets.SecretsManagerType]secrets.SecretsManagerFactory{
32 | secrets.Local: local.SecretsManagerFactory,
33 | secrets.HashicorpVault: hashicorpvault.SecretsManagerFactory,
34 | secrets.AWSSSM: awsssm.SecretsManagerFactory,
35 | secrets.GCPSSM: gcpssm.SecretsManagerFactory,
36 | }
37 |
38 | func ConsensusSupported(value string) bool {
39 | _, ok := consensusBackends[ConsensusType(value)]
40 |
41 | return ok
42 | }
43 |
--------------------------------------------------------------------------------
/server/config.go:
--------------------------------------------------------------------------------
1 | package server
2 |
3 | import (
4 | "net"
5 |
6 | "github.com/hashicorp/go-hclog"
7 |
8 | "github.com/ExzoNetwork/ExzoCoin/chain"
9 | "github.com/ExzoNetwork/ExzoCoin/network"
10 | "github.com/ExzoNetwork/ExzoCoin/secrets"
11 | )
12 |
13 | const DefaultGRPCPort int = 9632
14 | const DefaultJSONRPCPort int = 8545
15 |
16 | // Config is used to parametrize the minimal client
17 | type Config struct {
18 | Chain *chain.Chain
19 |
20 | JSONRPC *JSONRPC
21 | GRPCAddr *net.TCPAddr
22 | LibP2PAddr *net.TCPAddr
23 |
24 | PriceLimit uint64
25 | MaxAccountEnqueued uint64
26 | MaxSlots uint64
27 | BlockTime uint64
28 |
29 | Telemetry *Telemetry
30 | Network *network.Config
31 |
32 | DataDir string
33 | RestoreFile *string
34 |
35 | Seal bool
36 |
37 | SecretsManager *secrets.SecretsManagerConfig
38 |
39 | LogLevel hclog.Level
40 |
41 | JSONLogFormat bool
42 |
43 | LogFilePath string
44 | }
45 |
46 | // Telemetry holds the config details for metric services
47 | type Telemetry struct {
48 | PrometheusAddr *net.TCPAddr
49 | }
50 |
51 | // JSONRPC holds the config details for the JSON-RPC server
52 | type JSONRPC struct {
53 | JSONRPCAddr *net.TCPAddr
54 | AccessControlAllowOrigin []string
55 | BatchLengthLimit uint64
56 | BlockRangeLimit uint64
57 | }
58 |
--------------------------------------------------------------------------------
/server/proto/system.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package v1;
4 |
5 | option go_package = "/server/proto";
6 |
7 | import "google/protobuf/empty.proto";
8 |
9 | service System {
10 | // GetInfo returns info about the client
11 | rpc GetStatus(google.protobuf.Empty) returns (ServerStatus);
12 |
13 | // PeersAdd adds a new peer
14 | rpc PeersAdd(PeersAddRequest) returns (PeersAddResponse);
15 |
16 | // PeersList returns the list of peers
17 | rpc PeersList(google.protobuf.Empty) returns (PeersListResponse);
18 |
19 | // PeersInfo returns the info of a peer
20 | rpc PeersStatus(PeersStatusRequest) returns (Peer);
21 |
22 | // Subscribe subscribes to blockchain events
23 | rpc Subscribe(google.protobuf.Empty) returns (stream BlockchainEvent);
24 |
25 | // Export returns blockchain data
26 | rpc BlockByNumber(BlockByNumberRequest) returns (BlockResponse);
27 |
28 | // Export returns blockchain data
29 | rpc Export(ExportRequest) returns (stream ExportEvent);
30 | }
31 |
32 | message BlockchainEvent {
33 | repeated Header added = 1;
34 | repeated Header removed = 2;
35 |
36 | message Header {
37 | int64 number = 1;
38 | string hash = 2;
39 | }
40 | }
41 |
42 | message ServerStatus {
43 | int64 network = 1;
44 |
45 | string genesis = 2;
46 |
47 | Block current = 3;
48 |
49 | string p2pAddr = 4;
50 |
51 | message Block {
52 | int64 number = 1;
53 | string hash = 2;
54 | }
55 | }
56 |
57 | message Peer {
58 | string id = 1;
59 | repeated string protocols = 2;
60 | repeated string addrs = 3;
61 | }
62 |
63 | message PeersAddRequest {
64 | string id = 1;
65 | }
66 |
67 | message PeersAddResponse {
68 | string message = 1;
69 | }
70 |
71 | message PeersStatusRequest {
72 | string id = 1;
73 | }
74 |
75 | message PeersListResponse {
76 | repeated Peer peers = 1;
77 | }
78 |
79 | message BlockByNumberRequest {
80 | uint64 number = 1;
81 | }
82 |
83 | message BlockResponse {
84 | bytes data = 1;
85 | }
86 |
87 | message ExportRequest {
88 | uint64 from = 1;
89 | uint64 to = 2;
90 | }
91 |
92 | message ExportEvent {
93 | uint64 from = 1;
94 | // null when zero
95 | uint64 to = 2;
96 | uint64 latest = 3;
97 | bytes data = 4;
98 | }
99 |
--------------------------------------------------------------------------------
/state/immutable-trie/encoding.go:
--------------------------------------------------------------------------------
1 | package itrie
2 |
3 | // hasTerminator checks if hex is ending
4 | // with a terminator flag.
5 | func hasTerminator(hex []byte) bool {
6 | if len(hex) == 0 {
7 | return false
8 | }
9 |
10 | return hex[len(hex)-1] == 16
11 | }
12 |
13 | // encodeCompact packs a hex sequence (of nibbles)
14 | // into compact encoding.
15 | func encodeCompact(hex []byte) []byte {
16 | var terminator int
17 |
18 | if hasTerminator(hex) {
19 | // remove terminator flag
20 | hex = hex[:len(hex)-1]
21 | terminator = 1
22 | } else {
23 | terminator = 0
24 | }
25 |
26 | // determine prefix flag
27 | oddLen := len(hex) % 2
28 | flag := 2*terminator + oddLen
29 |
30 | // insert flag
31 | if oddLen == 1 {
32 | hex = append([]byte{byte(flag)}, hex...)
33 | } else {
34 | hex = append([]byte{byte(flag), byte(0)}, hex...)
35 | }
36 |
37 | // hex slice is of even length now - pack nibbles
38 | result := make([]byte, len(hex)/2)
39 | for i := 0; i < cap(result); i++ {
40 | result[i] = hex[2*i]<<4 | hex[2*i+1]
41 | }
42 |
43 | return result
44 | }
45 |
46 | // bytesToHexNibbles splits bytes into nibbles
47 | // (with terminator flag). Prefix flag is not removed.
48 | func bytesToHexNibbles(bytes []byte) []byte {
49 | nibbles := make([]byte, len(bytes)*2+1)
50 | for i, b := range bytes {
51 | nibbles[i*2] = b / 16
52 | nibbles[i*2+1] = b % 16
53 | }
54 |
55 | nibbles[len(nibbles)-1] = 16
56 |
57 | return nibbles
58 | }
59 |
60 | // decodeCompact unpacks compact encoding
61 | // into a hex sequence of nibbles.
62 | func decodeCompact(compact []byte) []byte {
63 | base := bytesToHexNibbles(compact)
64 |
65 | // remove the terminator flag
66 | if base[0] < 2 {
67 | base = base[:len(base)-1]
68 | }
69 |
70 | // remove prefix flag
71 | if base[0]&1 == 1 {
72 | // odd length
73 | base = base[1:]
74 | } else {
75 | // even length
76 | base = base[2:]
77 | }
78 |
79 | return base
80 | }
81 |
--------------------------------------------------------------------------------
/state/immutable-trie/snapshot.go:
--------------------------------------------------------------------------------
1 | package itrie
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/crypto"
5 | "github.com/ExzoNetwork/ExzoCoin/state"
6 | "github.com/ExzoNetwork/ExzoCoin/types"
7 | "github.com/umbracle/fastrlp"
8 | )
9 |
10 | type Snapshot struct {
11 | state *State
12 | trie *Trie
13 | }
14 |
15 | var emptyStateHash = types.StringToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
16 |
17 | func (s *Snapshot) GetStorage(addr types.Address, root types.Hash, rawkey types.Hash) types.Hash {
18 | var (
19 | err error
20 | trie *Trie
21 | )
22 |
23 | if root == emptyStateHash {
24 | trie = s.state.newTrie()
25 | } else {
26 | trie, err = s.state.newTrieAt(root)
27 | if err != nil {
28 | return types.Hash{}
29 | }
30 | }
31 |
32 | key := crypto.Keccak256(rawkey.Bytes())
33 |
34 | val, ok := trie.Get(key)
35 | if !ok {
36 | return types.Hash{}
37 | }
38 |
39 | p := &fastrlp.Parser{}
40 |
41 | v, err := p.Parse(val)
42 | if err != nil {
43 | return types.Hash{}
44 | }
45 |
46 | res := []byte{}
47 | if res, err = v.GetBytes(res[:0]); err != nil {
48 | return types.Hash{}
49 | }
50 |
51 | return types.BytesToHash(res)
52 | }
53 |
54 | func (s *Snapshot) GetAccount(addr types.Address) (*state.Account, error) {
55 | key := crypto.Keccak256(addr.Bytes())
56 |
57 | data, ok := s.trie.Get(key)
58 | if !ok {
59 | return nil, nil
60 | }
61 |
62 | var account state.Account
63 | if err := account.UnmarshalRlp(data); err != nil {
64 | return nil, err
65 | }
66 |
67 | return &account, nil
68 | }
69 |
70 | func (s *Snapshot) GetCode(hash types.Hash) ([]byte, bool) {
71 | return s.state.GetCode(hash)
72 | }
73 |
74 | func (s *Snapshot) Commit(objs []*state.Object) (state.Snapshot, []byte) {
75 | trie, root := s.trie.Commit(objs)
76 |
77 | return &Snapshot{trie: trie, state: s.state}, root
78 | }
79 |
--------------------------------------------------------------------------------
/state/immutable-trie/state_test.go:
--------------------------------------------------------------------------------
1 | package itrie
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/state"
7 | )
8 |
9 | func TestState(t *testing.T) {
10 | state.TestState(t, buildPreState)
11 | }
12 |
13 | func buildPreState(pre state.PreStates) state.Snapshot {
14 | storage := NewMemoryStorage()
15 | st := NewState(storage)
16 | snap := st.NewSnapshot()
17 |
18 | return snap
19 | }
20 |
--------------------------------------------------------------------------------
/state/runtime/evm/bitmap.go:
--------------------------------------------------------------------------------
1 | package evm
2 |
3 | const bitmapSize = uint(8)
4 |
5 | type bitmap struct {
6 | buf []byte
7 | }
8 |
9 | func (b *bitmap) isSet(i uint) bool {
10 | return b.buf[i/bitmapSize]&(1<<(i%bitmapSize)) != 0
11 | }
12 |
13 | func (b *bitmap) set(i uint) {
14 | b.buf[i/bitmapSize] |= 1 << (i % bitmapSize)
15 | }
16 |
17 | func (b *bitmap) reset() {
18 | for i := range b.buf {
19 | b.buf[i] = 0
20 | }
21 |
22 | b.buf = b.buf[:0]
23 | }
24 |
25 | func (b *bitmap) setCode(code []byte) {
26 | codeSize := uint(len(code))
27 | b.buf = extendByteSlice(b.buf, int(codeSize/bitmapSize+1))
28 |
29 | for i := uint(0); i < codeSize; {
30 | c := code[i]
31 |
32 | if isPushOp(c) {
33 | // push op
34 | i += uint(c - 0x60 + 2)
35 | } else {
36 | if c == 0x5B {
37 | // jumpdest
38 | b.set(i)
39 | }
40 | i++
41 | }
42 | }
43 | }
44 |
45 | func isPushOp(i byte) bool {
46 | // From PUSH1 (0x60) to PUSH32(0x7F)
47 | return i>>5 == 3
48 | }
49 |
--------------------------------------------------------------------------------
/state/runtime/evm/bitmap_test.go:
--------------------------------------------------------------------------------
1 | package evm
2 |
3 | import (
4 | "strings"
5 | "testing"
6 | )
7 |
8 | func TestIsPush(t *testing.T) {
9 | num := 0
10 |
11 | for i := 0x0; i < 0xFF; i++ {
12 | if i>>5 == 3 {
13 | if !strings.HasPrefix(OpCode(i).String(), "PUSH") {
14 | t.Fatal("err")
15 | }
16 | num++
17 | }
18 | }
19 |
20 | if num != 32 {
21 | t.Fatal("bad")
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/state/runtime/evm/dispatch_table_test.go:
--------------------------------------------------------------------------------
1 | package evm
2 |
3 | import (
4 | "bytes"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestPushOpcodes(t *testing.T) {
11 | code := make([]byte, 33)
12 | for i := 0; i < 33; i++ {
13 | code[i] = byte(i + 1)
14 | }
15 |
16 | c := 1
17 |
18 | for i := PUSH1; i <= PUSH32; i++ {
19 | s := &state{
20 | code: code,
21 | }
22 |
23 | inst := dispatchTable[i]
24 | inst.inst(s)
25 |
26 | assert.False(t, s.stop)
27 |
28 | res := s.pop().Bytes()
29 | assert.Len(t, res, c)
30 |
31 | assert.True(t, bytes.HasPrefix(code[1:], res))
32 | c++
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/state/runtime/evm/evm.go:
--------------------------------------------------------------------------------
1 | package evm
2 |
3 | import (
4 | "errors"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/chain"
7 | "github.com/ExzoNetwork/ExzoCoin/state/runtime"
8 | )
9 |
10 | var _ runtime.Runtime = &EVM{}
11 |
12 | // EVM is the ethereum virtual machine
13 | type EVM struct {
14 | }
15 |
16 | // NewEVM creates a new EVM
17 | func NewEVM() *EVM {
18 | return &EVM{}
19 | }
20 |
21 | // CanRun implements the runtime interface
22 | func (e *EVM) CanRun(*runtime.Contract, runtime.Host, *chain.ForksInTime) bool {
23 | return true
24 | }
25 |
26 | // Name implements the runtime interface
27 | func (e *EVM) Name() string {
28 | return "evm"
29 | }
30 |
31 | // Run implements the runtime interface
32 | func (e *EVM) Run(c *runtime.Contract, host runtime.Host, config *chain.ForksInTime) *runtime.ExecutionResult {
33 | contract := acquireState()
34 | contract.resetReturnData()
35 |
36 | contract.msg = c
37 | contract.code = c.Code
38 | contract.evm = e
39 | contract.gas = c.Gas
40 | contract.host = host
41 | contract.config = config
42 |
43 | contract.bitmap.setCode(c.Code)
44 |
45 | ret, err := contract.Run()
46 |
47 | // We are probably doing this append magic to make sure that the slice doesn't have more capacity than it needs
48 | var returnValue []byte
49 | returnValue = append(returnValue[:0], ret...)
50 |
51 | gasLeft := contract.gas
52 |
53 | releaseState(contract)
54 |
55 | if err != nil && !errors.Is(err, errRevert) {
56 | gasLeft = 0
57 | }
58 |
59 | return &runtime.ExecutionResult{
60 | ReturnValue: returnValue,
61 | GasLeft: gasLeft,
62 | GasUsed: c.Gas - gasLeft,
63 | Err: err,
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/state/runtime/evm/opcodes_test.go:
--------------------------------------------------------------------------------
1 | package evm
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/assert"
7 | )
8 |
9 | func TestOpcodesString(t *testing.T) {
10 | assert := func(op OpCode, str string) {
11 | assert.Equal(t, op.String(), str)
12 | }
13 |
14 | assert(PUSH1, "PUSH1")
15 | assert(PUSH32, "PUSH32")
16 |
17 | assert(LOG0, "LOG0")
18 | assert(LOG4, "LOG4")
19 |
20 | assert(SWAP1, "SWAP1")
21 | assert(SWAP16, "SWAP16")
22 |
23 | assert(DUP1, "DUP1")
24 | assert(DUP16, "DUP16")
25 |
26 | assert(OpCode(0xA5), "")
27 | }
28 |
--------------------------------------------------------------------------------
/state/runtime/precompiled/blake2f_test.go:
--------------------------------------------------------------------------------
1 | package precompiled
2 |
3 | import (
4 | "bytes"
5 | "testing"
6 | )
7 |
8 | func TestBlake2f(t *testing.T) {
9 | b := &blake2f{}
10 |
11 | ReadTestCase(t, "blake2f.json", func(t *testing.T, c *TestCase) {
12 | t.Helper()
13 |
14 | out, err := b.run(c.Input)
15 | if err != nil {
16 | t.Fatal(err)
17 | }
18 | if !bytes.Equal(c.Expected, out) {
19 | t.Fatal("bad")
20 | }
21 | })
22 | }
23 |
--------------------------------------------------------------------------------
/state/runtime/precompiled/testing.go:
--------------------------------------------------------------------------------
1 | package precompiled
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "os"
7 | "path/filepath"
8 | "testing"
9 |
10 | "github.com/ExzoNetwork/ExzoCoin/helper/hex"
11 | )
12 |
13 | type TestCase struct {
14 | Name string
15 | Input []byte
16 | Expected []byte
17 | Gas uint64
18 | }
19 |
20 | // decodeHex is a helper function for decoding a hex string
21 | func decodeHex(t *testing.T, input string) []byte {
22 | t.Helper()
23 |
24 | inputDecode, decodeErr := hex.DecodeHex(input)
25 | if decodeErr != nil {
26 | t.Fatalf("unable to decode hex, %v", decodeErr)
27 | }
28 |
29 | return inputDecode
30 | }
31 |
32 | func ReadTestCase(t *testing.T, path string, f func(t *testing.T, c *TestCase)) {
33 | t.Helper()
34 | t.Parallel()
35 |
36 | data, err := os.ReadFile(filepath.Join("./fixtures", path))
37 | if err != nil {
38 | t.Fatal(err)
39 | }
40 |
41 | type testCase struct {
42 | Name string
43 | Input string
44 | Expected string
45 | Gas uint64
46 | }
47 |
48 | var cases []*testCase
49 |
50 | if err := json.Unmarshal(data, &cases); err != nil {
51 | t.Fatal(err)
52 | }
53 |
54 | for _, i := range cases {
55 | i := i
56 |
57 | inputDecode := decodeHex(t, fmt.Sprintf("0x%s", i.Input))
58 | expectedDecode := decodeHex(t, fmt.Sprintf("0x%s", i.Expected))
59 |
60 | c := &TestCase{
61 | Name: i.Name,
62 | Gas: i.Gas,
63 | Input: inputDecode,
64 | Expected: expectedDecode,
65 | }
66 |
67 | t.Run(i.Name, func(t *testing.T) {
68 | t.Parallel()
69 |
70 | f(t, c)
71 | })
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/state/runtime/tracer/types.go:
--------------------------------------------------------------------------------
1 | package tracer
2 |
3 | import (
4 | "math/big"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/types"
7 | )
8 |
9 | // RuntimeHost is the interface defining the methods for accessing state by tracer
10 | type RuntimeHost interface {
11 | // GetRefund returns refunded value
12 | GetRefund() uint64
13 | // GetStorage access the storage slot at the given address and slot hash
14 | GetStorage(types.Address, types.Hash) types.Hash
15 | }
16 |
17 | type VMState interface {
18 | // Halt tells VM to terminate its process
19 | Halt()
20 | }
21 |
22 | type Tracer interface {
23 | // Cancel tells termination of execution and tracing
24 | Cancel(error)
25 | // Clear clears the tracked data
26 | Clear()
27 | // GetResult returns a result based on tracked data
28 | GetResult() (interface{}, error)
29 |
30 | // Tx-level
31 | TxStart(gasLimit uint64)
32 | TxEnd(gasLeft uint64)
33 |
34 | // Call-level
35 | CallStart(
36 | depth int, // begins from 1
37 | from, to types.Address,
38 | callType int,
39 | gas uint64,
40 | value *big.Int,
41 | input []byte,
42 | )
43 | CallEnd(
44 | depth int, // begins from 1
45 | output []byte,
46 | err error,
47 | )
48 |
49 | // Op-level
50 | CaptureState(
51 | memory []byte,
52 | stack []*big.Int,
53 | opCode int,
54 | contractAddress types.Address,
55 | sp int,
56 | host RuntimeHost,
57 | state VMState,
58 | )
59 | ExecuteState(
60 | contractAddress types.Address,
61 | ip uint64,
62 | opcode string,
63 | availableGas uint64,
64 | cost uint64,
65 | lastReturnData []byte,
66 | depth int,
67 | err error,
68 | host RuntimeHost,
69 | )
70 | }
71 |
--------------------------------------------------------------------------------
/state/txn_test.go:
--------------------------------------------------------------------------------
1 | package state
2 |
3 | import (
4 | "fmt"
5 | "math/big"
6 | "testing"
7 |
8 | "github.com/ExzoNetwork/ExzoCoin/types"
9 | "github.com/stretchr/testify/assert"
10 | )
11 |
12 | type mockSnapshot struct {
13 | state map[types.Address]*PreState
14 | }
15 |
16 | func (m *mockSnapshot) GetStorage(addr types.Address, root types.Hash, key types.Hash) types.Hash {
17 | raw, ok := m.state[addr]
18 | if !ok {
19 | return types.Hash{}
20 | }
21 |
22 | res, ok := raw.State[key]
23 | if !ok {
24 | return types.Hash{}
25 | }
26 |
27 | return res
28 | }
29 |
30 | func (m *mockSnapshot) GetAccount(addr types.Address) (*Account, error) {
31 | raw, ok := m.state[addr]
32 | if !ok {
33 | return nil, fmt.Errorf("account not found")
34 | }
35 |
36 | acct := &Account{
37 | Balance: new(big.Int).SetUint64(raw.Balance),
38 | Nonce: raw.Nonce,
39 | }
40 |
41 | return acct, nil
42 | }
43 |
44 | func (m *mockSnapshot) GetCode(hash types.Hash) ([]byte, bool) {
45 | return nil, false
46 | }
47 |
48 | func newStateWithPreState(preState map[types.Address]*PreState) readSnapshot {
49 | return &mockSnapshot{state: preState}
50 | }
51 |
52 | func newTestTxn(p map[types.Address]*PreState) *Txn {
53 | return newTxn(newStateWithPreState(p))
54 | }
55 |
56 | func TestSnapshotUpdateData(t *testing.T) {
57 | txn := newTestTxn(defaultPreState)
58 |
59 | txn.SetState(addr1, hash1, hash1)
60 | assert.Equal(t, hash1, txn.GetState(addr1, hash1))
61 |
62 | ss := txn.Snapshot()
63 | txn.SetState(addr1, hash1, hash2)
64 | assert.Equal(t, hash2, txn.GetState(addr1, hash1))
65 |
66 | txn.RevertToSnapshot(ss)
67 | assert.Equal(t, hash1, txn.GetState(addr1, hash1))
68 | }
69 |
--------------------------------------------------------------------------------
/syncer/peers.go:
--------------------------------------------------------------------------------
1 | package syncer
2 |
3 | import (
4 | "math/big"
5 | "sync"
6 |
7 | "github.com/libp2p/go-libp2p/core/peer"
8 | )
9 |
10 | type NoForkPeer struct {
11 | // identifier
12 | ID peer.ID
13 | // peer's latest block number
14 | Number uint64
15 | // peer's distance
16 | Distance *big.Int
17 | }
18 |
19 | func (p *NoForkPeer) IsBetter(t *NoForkPeer) bool {
20 | if p.Number != t.Number {
21 | return p.Number > t.Number
22 | }
23 |
24 | return p.Distance.Cmp(t.Distance) < 0
25 | }
26 |
27 | type PeerMap struct {
28 | sync.Map
29 | }
30 |
31 | func NewPeerMap(peers []*NoForkPeer) *PeerMap {
32 | peerMap := new(PeerMap)
33 |
34 | peerMap.Put(peers...)
35 |
36 | return peerMap
37 | }
38 |
39 | func (m *PeerMap) Put(peers ...*NoForkPeer) {
40 | for _, peer := range peers {
41 | m.Store(peer.ID.String(), peer)
42 | }
43 | }
44 |
45 | // Remove removes a peer from heap if it exists
46 | func (m *PeerMap) Remove(peerID peer.ID) {
47 | m.Delete(peerID.String())
48 | }
49 |
50 | // BestPeer returns the top of heap
51 | func (m *PeerMap) BestPeer(skipMap map[peer.ID]bool) *NoForkPeer {
52 | var bestPeer *NoForkPeer
53 |
54 | m.Range(func(key, value interface{}) bool {
55 | peer, _ := value.(*NoForkPeer)
56 |
57 | if skipMap != nil && skipMap[peer.ID] {
58 | return true
59 | }
60 |
61 | if bestPeer == nil || peer.IsBetter(bestPeer) {
62 | bestPeer = peer
63 | }
64 |
65 | return true
66 | })
67 |
68 | return bestPeer
69 | }
70 |
--------------------------------------------------------------------------------
/syncer/proto/syncer.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package v1;
4 |
5 | option go_package = "/syncer/proto";
6 |
7 | import "google/protobuf/empty.proto";
8 |
9 | service SyncPeer {
10 | // Returns stream of blocks beginning specified from
11 | rpc GetBlocks(GetBlocksRequest) returns (stream Block);
12 | // Returns server's status
13 | rpc GetStatus(google.protobuf.Empty) returns (SyncPeerStatus);
14 | }
15 |
16 | // GetBlocksRequest is a request for GetBlocks
17 | message GetBlocksRequest {
18 | // The height of beginning block to sync
19 | uint64 from = 1;
20 | }
21 |
22 | // Block contains a block data
23 | message Block {
24 | // RLP Encoded Block Data
25 | bytes block = 1;
26 | }
27 |
28 | // SyncPeerStatus contains peer status
29 | message SyncPeerStatus {
30 | // Latest block height
31 | uint64 number = 1;
32 | }
33 |
--------------------------------------------------------------------------------
/txpool/event_queue.go:
--------------------------------------------------------------------------------
1 | package txpool
2 |
3 | import (
4 | "sync"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/txpool/proto"
7 | )
8 |
9 | type eventQueue struct {
10 | events []*proto.TxPoolEvent
11 | sync.Mutex
12 | }
13 |
14 | func (es *eventQueue) push(event *proto.TxPoolEvent) {
15 | es.Lock()
16 | defer es.Unlock()
17 |
18 | es.events = append(es.events, event)
19 | }
20 |
21 | func (es *eventQueue) pop() *proto.TxPoolEvent {
22 | es.Lock()
23 | defer es.Unlock()
24 |
25 | if len(es.events) == 0 {
26 | return nil
27 | }
28 |
29 | event := es.events[0]
30 | es.events = es.events[1:]
31 |
32 | return event
33 | }
34 |
--------------------------------------------------------------------------------
/txpool/lookup_map.go:
--------------------------------------------------------------------------------
1 | package txpool
2 |
3 | import (
4 | "sync"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/types"
7 | )
8 |
9 | // Lookup map used to find transactions present in the pool
10 | type lookupMap struct {
11 | sync.RWMutex
12 | all map[types.Hash]*types.Transaction
13 | }
14 |
15 | // add inserts the given transaction into the map. Returns false
16 | // if it already exists. [thread-safe]
17 | func (m *lookupMap) add(tx *types.Transaction) bool {
18 | m.Lock()
19 | defer m.Unlock()
20 |
21 | if _, exists := m.all[tx.Hash]; exists {
22 | return false
23 | }
24 |
25 | m.all[tx.Hash] = tx
26 |
27 | return true
28 | }
29 |
30 | // remove removes the given transactions from the map. [thread-safe]
31 | func (m *lookupMap) remove(txs ...*types.Transaction) {
32 | m.Lock()
33 | defer m.Unlock()
34 |
35 | for _, tx := range txs {
36 | delete(m.all, tx.Hash)
37 | }
38 | }
39 |
40 | // get returns the transaction associated with the given hash. [thread-safe]
41 | func (m *lookupMap) get(hash types.Hash) (*types.Transaction, bool) {
42 | m.RLock()
43 | defer m.RUnlock()
44 |
45 | tx, ok := m.all[hash]
46 | if !ok {
47 | return nil, false
48 | }
49 |
50 | return tx, true
51 | }
52 |
--------------------------------------------------------------------------------
/txpool/mock_test.go:
--------------------------------------------------------------------------------
1 | package txpool
2 |
3 | import (
4 | "fmt"
5 | "math/big"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/types"
8 | )
9 |
10 | var mockHeader = &types.Header{
11 | GasLimit: 4712388,
12 | }
13 |
14 | /* MOCK */
15 |
16 | type defaultMockStore struct {
17 | DefaultHeader *types.Header
18 | }
19 |
20 | func NewDefaultMockStore(header *types.Header) defaultMockStore {
21 | return defaultMockStore{
22 | header,
23 | }
24 | }
25 |
26 | func (m defaultMockStore) Header() *types.Header {
27 | return m.DefaultHeader
28 | }
29 |
30 | func (m defaultMockStore) GetNonce(types.Hash, types.Address) uint64 {
31 | return 0
32 | }
33 |
34 | func (m defaultMockStore) GetBlockByHash(types.Hash, bool) (*types.Block, bool) {
35 | return nil, false
36 | }
37 |
38 | func (m defaultMockStore) GetBalance(types.Hash, types.Address) (*big.Int, error) {
39 | balance := big.NewInt(0).SetUint64(100000000000000)
40 |
41 | return balance, nil
42 | }
43 |
44 | type faultyMockStore struct {
45 | }
46 |
47 | func (fms faultyMockStore) Header() *types.Header {
48 | return &types.Header{}
49 | }
50 |
51 | func (fms faultyMockStore) GetNonce(root types.Hash, addr types.Address) uint64 {
52 | return 99999
53 | }
54 |
55 | func (fms faultyMockStore) GetBlockByHash(hash types.Hash, b bool) (*types.Block, bool) {
56 | return nil, false
57 | }
58 |
59 | func (fms faultyMockStore) GetBalance(root types.Hash, addr types.Address) (*big.Int, error) {
60 | return nil, fmt.Errorf("unable to fetch account state")
61 | }
62 |
63 | type mockSigner struct {
64 | }
65 |
66 | func (s *mockSigner) Sender(tx *types.Transaction) (types.Address, error) {
67 | return tx.From, nil
68 | }
69 |
--------------------------------------------------------------------------------
/txpool/operator.go:
--------------------------------------------------------------------------------
1 | package txpool
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | "github.com/ExzoNetwork/ExzoCoin/txpool/proto"
8 | "github.com/ExzoNetwork/ExzoCoin/types"
9 | empty "google.golang.org/protobuf/types/known/emptypb"
10 | )
11 |
12 | // Status implements the GRPC status endpoint. Returns the number of transactions in the pool
13 | func (p *TxPool) Status(ctx context.Context, req *empty.Empty) (*proto.TxnPoolStatusResp, error) {
14 | resp := &proto.TxnPoolStatusResp{
15 | Length: p.accounts.promoted(),
16 | }
17 |
18 | return resp, nil
19 | }
20 |
21 | // AddTxn adds a local transaction to the pool
22 | func (p *TxPool) AddTxn(ctx context.Context, raw *proto.AddTxnReq) (*proto.AddTxnResp, error) {
23 | if raw.Raw == nil {
24 | return nil, fmt.Errorf("transaction's field raw is empty")
25 | }
26 |
27 | txn := new(types.Transaction)
28 | if err := txn.UnmarshalRLP(raw.Raw.Value); err != nil {
29 | return nil, err
30 | }
31 |
32 | if raw.From != "" {
33 | from := types.Address{}
34 | if err := from.UnmarshalText([]byte(raw.From)); err != nil {
35 | return nil, err
36 | }
37 |
38 | txn.From = from
39 | }
40 |
41 | if err := p.AddTx(txn); err != nil {
42 | return nil, err
43 | }
44 |
45 | return &proto.AddTxnResp{
46 | TxHash: txn.Hash.String(),
47 | }, nil
48 | }
49 |
50 | // Subscribe implements the operator endpoint. It subscribes to new events in the tx pool
51 | func (p *TxPool) Subscribe(
52 | request *proto.SubscribeRequest,
53 | stream proto.TxnPoolOperator_SubscribeServer,
54 | ) error {
55 | subscription := p.eventManager.subscribe(request.Types)
56 |
57 | cancel := func() {
58 | p.eventManager.cancelSubscription(subscription.subscriptionID)
59 | }
60 |
61 | for {
62 | select {
63 | case event, more := <-subscription.subscriptionChannel:
64 | if !more {
65 | // Subscription is closed from some other place
66 | return nil
67 | }
68 |
69 | if sendErr := stream.Send(event); sendErr != nil {
70 | cancel()
71 |
72 | return nil
73 | }
74 | case <-stream.Context().Done():
75 | cancel()
76 |
77 | return nil
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/txpool/proto/operator.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package v1;
4 |
5 | option go_package = "/txpool/proto";
6 |
7 | import "google/protobuf/any.proto";
8 | import "google/protobuf/empty.proto";
9 |
10 | service TxnPoolOperator {
11 | // Status returns the current status of the pool
12 | rpc Status(google.protobuf.Empty) returns (TxnPoolStatusResp);
13 |
14 | // AddTxn adds a local transaction to the pool
15 | rpc AddTxn(AddTxnReq) returns (AddTxnResp);
16 |
17 | // Subscribe subscribes for new events in the txpool
18 | rpc Subscribe(SubscribeRequest) returns (stream TxPoolEvent);
19 | }
20 |
21 | message AddTxnReq {
22 | google.protobuf.Any raw = 1;
23 | string from = 2;
24 | }
25 |
26 | message AddTxnResp {
27 | string txHash = 1;
28 | }
29 |
30 | message TxnPoolStatusResp {
31 | uint64 length = 1;
32 | }
33 |
34 | message SubscribeRequest {
35 | // Requested event types
36 | repeated EventType types = 1;
37 | }
38 |
39 | enum EventType {
40 | // For initially added transactions
41 | ADDED = 0;
42 |
43 | // For enqueued transactions in the account queue
44 | ENQUEUED = 1;
45 |
46 | // For promoted transactions
47 | PROMOTED = 2;
48 |
49 | // For dropped transactions
50 | DROPPED = 3;
51 |
52 | // For demoted transactions
53 | DEMOTED = 4;
54 |
55 | // For pruned promoted transactions
56 | PRUNED_PROMOTED = 5;
57 |
58 | // For pruned enqueued transactions
59 | PRUNED_ENQUEUED = 6;
60 | }
61 |
62 | message TxPoolEvent {
63 | EventType type = 1;
64 | string txHash = 2;
65 | }
66 |
--------------------------------------------------------------------------------
/txpool/proto/v1.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package v1;
4 |
5 | option go_package = "/txpool/proto";
6 |
7 | import "google/protobuf/any.proto";
8 |
9 | message Txn {
10 | google.protobuf.Any raw = 1;
11 | }
12 |
--------------------------------------------------------------------------------
/txpool/query.go:
--------------------------------------------------------------------------------
1 | package txpool
2 |
3 | import "github.com/ExzoNetwork/ExzoCoin/types"
4 |
5 | /* QUERY methods */
6 | // Used to query the pool for specific state info.
7 |
8 | // GetNonce returns the next nonce for the account
9 | //
10 | // -> Returns the value from the TxPool if the account is initialized in-memory
11 | //
12 | // -> Returns the value from the world state otherwise
13 | func (p *TxPool) GetNonce(addr types.Address) uint64 {
14 | account := p.accounts.get(addr)
15 | if account == nil {
16 | stateRoot := p.store.Header().StateRoot
17 | stateNonce := p.store.GetNonce(stateRoot, addr)
18 |
19 | return stateNonce
20 | }
21 |
22 | return account.getNonce()
23 | }
24 |
25 | // GetCapacity returns the current number of slots
26 | // occupied in the pool as well as the max limit
27 | func (p *TxPool) GetCapacity() (uint64, uint64) {
28 | return p.gauge.read(), p.gauge.max
29 | }
30 |
31 | // GetPendingTx returns the transaction by hash in the TxPool (pending txn) [Thread-safe]
32 | func (p *TxPool) GetPendingTx(txHash types.Hash) (*types.Transaction, bool) {
33 | tx, ok := p.index.get(txHash)
34 | if !ok {
35 | return nil, false
36 | }
37 |
38 | return tx, true
39 | }
40 |
41 | // GetTxs gets pending and queued transactions
42 | func (p *TxPool) GetTxs(inclQueued bool) (
43 | allPromoted, allEnqueued map[types.Address][]*types.Transaction,
44 | ) {
45 | allPromoted, allEnqueued = p.accounts.allTxs(inclQueued)
46 |
47 | return
48 | }
49 |
--------------------------------------------------------------------------------
/txpool/slot_gauge.go:
--------------------------------------------------------------------------------
1 | package txpool
2 |
3 | import (
4 | "sync/atomic"
5 |
6 | "github.com/ExzoNetwork/ExzoCoin/types"
7 | )
8 |
9 | const (
10 | highPressureMark = 80 // 80%
11 | )
12 |
13 | // Gauge for measuring pool capacity in slots
14 | type slotGauge struct {
15 | height uint64 // amount of slots currently occupying the pool
16 | max uint64 // max limit
17 | }
18 |
19 | // read returns the current height of the gauge.
20 | func (g *slotGauge) read() uint64 {
21 | return atomic.LoadUint64(&g.height)
22 | }
23 |
24 | // increase increases the height of the gauge by the specified slots amount.
25 | func (g *slotGauge) increase(slots uint64) {
26 | atomic.AddUint64(&g.height, slots)
27 | }
28 |
29 | // decrease decreases the height of the gauge by the specified slots amount.
30 | func (g *slotGauge) decrease(slots uint64) {
31 | atomic.AddUint64(&g.height, ^(slots - 1))
32 | }
33 |
34 | // highPressure checks if the gauge level
35 | // is higher than the 0.8*max threshold
36 | func (g *slotGauge) highPressure() bool {
37 | return g.read() > (highPressureMark*g.max)/100
38 | }
39 |
40 | // slotsRequired calculates the number of slots required for given transaction(s).
41 | func slotsRequired(txs ...*types.Transaction) uint64 {
42 | slots := uint64(0)
43 | for _, tx := range txs {
44 | slots += (tx.Size() + txSlotSize - 1) / txSlotSize
45 | }
46 |
47 | return slots
48 | }
49 |
--------------------------------------------------------------------------------
/types/buildroot/buildroot_fast_test.go:
--------------------------------------------------------------------------------
1 | package buildroot
2 |
3 | import (
4 | "bytes"
5 | "crypto/rand"
6 | "math/big"
7 | "testing"
8 |
9 | "github.com/ExzoNetwork/ExzoCoin/helper/keccak"
10 | )
11 |
12 | func BenchmarkFast(b *testing.B) {
13 | f := acquireFastHasher()
14 |
15 | res := buildInput(128, 100)
16 |
17 | b.ResetTimer()
18 | b.ReportAllocs()
19 |
20 | for i := 0; i < b.N; i++ {
21 | f.Hash(128, res)
22 | f.reset()
23 | }
24 | }
25 |
26 | func BenchmarkSlow(b *testing.B) {
27 | res := buildInput(128, 100)
28 |
29 | b.ResetTimer()
30 | b.ReportAllocs()
31 |
32 | for i := 0; i < b.N; i++ {
33 | deriveSlow(128, res)
34 | }
35 | }
36 |
37 | func TestFastHasher(t *testing.T) {
38 | f := FastHasher{
39 | k: keccak.NewKeccak256(),
40 | }
41 |
42 | for i := 0; i < 1000; i++ {
43 | num := randomInt(1, 128)
44 | res := buildRandomInput(int(num))
45 |
46 | found, _ := f.Hash(int(num), res)
47 | realRes := deriveSlow(int(num), res)
48 |
49 | if !bytes.Equal(found, realRes) {
50 | t.Fatal("bad")
51 | }
52 |
53 | f.reset()
54 | }
55 | }
56 |
57 | func randomInt(min, max uint64) uint64 {
58 | randNum, _ := rand.Int(rand.Reader, big.NewInt(int64(max-min)))
59 |
60 | return min + randNum.Uint64()
61 | }
62 |
63 | func buildInput(n, m int) func(i int) []byte {
64 | res := [][]byte{}
65 |
66 | for i := 0; i < n; i++ {
67 | b := make([]byte, m)
68 | for indx := range b {
69 | b[indx] = byte(i)
70 | }
71 |
72 | res = append(res, b)
73 | }
74 |
75 | return func(i int) []byte {
76 | return res[i]
77 | }
78 | }
79 |
80 | func buildRandomInput(num int) func(i int) []byte {
81 | res := [][]byte{}
82 |
83 | for i := 0; i < num; i++ {
84 | b := make([]byte, randomInt(33, 200))
85 | _, _ = rand.Read(b)
86 | res = append(res, b)
87 | }
88 |
89 | return func(i int) []byte {
90 | return res[i]
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/types/encoding.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "fmt"
5 | "math/big"
6 | "strconv"
7 | "strings"
8 |
9 | "github.com/ExzoNetwork/ExzoCoin/helper/hex"
10 | )
11 |
12 | func ParseUint64orHex(val *string) (uint64, error) {
13 | if val == nil {
14 | return 0, nil
15 | }
16 |
17 | str := *val
18 | base := 10
19 |
20 | if strings.HasPrefix(str, "0x") {
21 | str = str[2:]
22 | base = 16
23 | }
24 |
25 | return strconv.ParseUint(str, base, 64)
26 | }
27 |
28 | func ParseUint256orHex(val *string) (*big.Int, error) {
29 | if val == nil {
30 | return nil, nil
31 | }
32 |
33 | str := *val
34 | base := 10
35 |
36 | if strings.HasPrefix(str, "0x") {
37 | str = str[2:]
38 | base = 16
39 | }
40 |
41 | b, ok := new(big.Int).SetString(str, base)
42 |
43 | if !ok {
44 | return nil, fmt.Errorf("could not parse")
45 | }
46 |
47 | return b, nil
48 | }
49 |
50 | func ParseInt64orHex(val *string) (int64, error) {
51 | i, err := ParseUint64orHex(val)
52 |
53 | return int64(i), err
54 | }
55 |
56 | func ParseBytes(val *string) ([]byte, error) {
57 | if val == nil {
58 | return []byte{}, nil
59 | }
60 |
61 | str := strings.TrimPrefix(*val, "0x")
62 |
63 | return hex.DecodeString(str)
64 | }
65 |
66 | func EncodeUint64(b uint64) *string {
67 | res := fmt.Sprintf("0x%x", b)
68 |
69 | return &res
70 | }
71 |
72 | func EncodeBytes(b []byte) *string {
73 | res := "0x" + hex.EncodeToString(b)
74 |
75 | return &res
76 | }
77 |
78 | func EncodeBigInt(b *big.Int) *string {
79 | res := "0x" + b.Text(16)
80 |
81 | return &res
82 | }
83 |
--------------------------------------------------------------------------------
/types/header_hash.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/helper/keccak"
5 | "github.com/umbracle/fastrlp"
6 | )
7 |
8 | var HeaderHash func(h *Header) Hash
9 |
10 | // This is the default header hash for the block.
11 | // In IBFT, this header hash method is substituted
12 | // for Istanbul Header Hash calculation
13 | func init() {
14 | HeaderHash = defHeaderHash
15 | }
16 |
17 | var marshalArenaPool fastrlp.ArenaPool
18 |
19 | func defHeaderHash(h *Header) (hash Hash) {
20 | // default header hashing
21 | ar := marshalArenaPool.Get()
22 | hasher := keccak.DefaultKeccakPool.Get()
23 |
24 | v := h.MarshalRLPWith(ar)
25 | hasher.WriteRlp(hash[:0], v)
26 |
27 | marshalArenaPool.Put(ar)
28 | keccak.DefaultKeccakPool.Put(hasher)
29 |
30 | return
31 | }
32 |
33 | // ComputeHash computes the hash of the header
34 | func (h *Header) ComputeHash() *Header {
35 | h.Hash = HeaderHash(h)
36 |
37 | return h
38 | }
39 |
--------------------------------------------------------------------------------
/types/rlp_marshal_storage.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "github.com/umbracle/fastrlp"
5 | )
6 |
7 | type RLPStoreMarshaler interface {
8 | MarshalStoreRLPTo(dst []byte) []byte
9 | }
10 |
11 | func (b *Body) MarshalRLPTo(dst []byte) []byte {
12 | return MarshalRLPTo(b.MarshalRLPWith, dst)
13 | }
14 |
15 | func (b *Body) MarshalRLPWith(ar *fastrlp.Arena) *fastrlp.Value {
16 | vv := ar.NewArray()
17 | if len(b.Transactions) == 0 {
18 | vv.Set(ar.NewNullArray())
19 | } else {
20 | v0 := ar.NewArray()
21 | for _, tx := range b.Transactions {
22 | v0.Set(tx.MarshalStoreRLPWith(ar))
23 | }
24 | vv.Set(v0)
25 | }
26 |
27 | if len(b.Uncles) == 0 {
28 | vv.Set(ar.NewNullArray())
29 | } else {
30 | v1 := ar.NewArray()
31 | for _, uncle := range b.Uncles {
32 | v1.Set(uncle.MarshalRLPWith(ar))
33 | }
34 | vv.Set(v1)
35 | }
36 |
37 | return vv
38 | }
39 |
40 | func (t *Transaction) MarshalStoreRLPTo(dst []byte) []byte {
41 | return MarshalRLPTo(t.MarshalStoreRLPWith, dst)
42 | }
43 |
44 | func (t *Transaction) MarshalStoreRLPWith(a *fastrlp.Arena) *fastrlp.Value {
45 | vv := a.NewArray()
46 | // consensus part
47 | vv.Set(t.MarshalRLPWith(a))
48 | // context part
49 | vv.Set(a.NewBytes(t.From.Bytes()))
50 |
51 | return vv
52 | }
53 |
54 | func (r Receipts) MarshalStoreRLPTo(dst []byte) []byte {
55 | return MarshalRLPTo(r.MarshalStoreRLPWith, dst)
56 | }
57 |
58 | func (r *Receipts) MarshalStoreRLPWith(a *fastrlp.Arena) *fastrlp.Value {
59 | vv := a.NewArray()
60 | for _, rr := range *r {
61 | vv.Set(rr.MarshalStoreRLPWith(a))
62 | }
63 |
64 | return vv
65 | }
66 |
67 | func (r *Receipt) MarshalStoreRLPTo(dst []byte) []byte {
68 | return MarshalRLPTo(r.MarshalStoreRLPWith, dst)
69 | }
70 |
71 | func (r *Receipt) MarshalStoreRLPWith(a *fastrlp.Arena) *fastrlp.Value {
72 | // use the hash part
73 | vv := a.NewArray()
74 | vv.Set(r.MarshalRLPWith(a))
75 |
76 | if r.ContractAddress == nil {
77 | vv.Set(a.NewNull())
78 | } else {
79 | vv.Set(a.NewBytes(r.ContractAddress.Bytes()))
80 | }
81 |
82 | // gas used
83 | vv.Set(a.NewUint(r.GasUsed))
84 |
85 | // TxHash
86 | vv.Set(a.NewBytes(r.TxHash.Bytes()))
87 |
88 | return vv
89 | }
90 |
--------------------------------------------------------------------------------
/types/types_test.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "math/big"
5 | "reflect"
6 | "testing"
7 |
8 | "github.com/stretchr/testify/assert"
9 | )
10 |
11 | func TestEIP55(t *testing.T) {
12 | t.Parallel()
13 |
14 | cases := []struct {
15 | address string
16 | expected string
17 | }{
18 | {
19 | "0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed",
20 | "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
21 | },
22 | {
23 | "0xfb6916095ca1df60bb79ce92ce3ea74c37c5d359",
24 | "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359",
25 | },
26 | {
27 | "0xdbf03b407c01e7cd3cbea99509d93f8dddc8c6fb",
28 | "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB",
29 | },
30 | {
31 | "0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb",
32 | "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb",
33 | },
34 | {
35 | "0xde64a66c41599905950ca513fa432187a8c65679",
36 | "0xde64A66C41599905950ca513Fa432187a8C65679",
37 | },
38 | {
39 | "0xb41364957365228984ea8ee98e80dbed4b9ffcdc",
40 | "0xB41364957365228984eA8EE98e80DBED4B9fFcDC",
41 | },
42 | {
43 | "0xb529594951753de833b00865d7fe52cc4d8b0f63",
44 | "0xB529594951753DE833b00865D7FE52cC4d8B0f63",
45 | },
46 | {
47 | "0xb529594951753de833b00865",
48 | "0x0000000000000000B529594951753De833B00865",
49 | },
50 | {
51 | "0xeEd210D",
52 | "0x000000000000000000000000000000000eED210d",
53 | },
54 | }
55 |
56 | for _, c := range cases {
57 | c := c
58 |
59 | t.Run("", func(t *testing.T) {
60 | t.Parallel()
61 |
62 | addr := StringToAddress(c.address)
63 | assert.Equal(t, c.expected, addr.String())
64 | })
65 | }
66 | }
67 |
68 | func TestTransactionCopy(t *testing.T) {
69 | addrTo := StringToAddress("11")
70 | txn := &Transaction{
71 | Nonce: 0,
72 | GasPrice: big.NewInt(11),
73 | Gas: 11,
74 | To: &addrTo,
75 | Value: big.NewInt(1),
76 | Input: []byte{1, 2},
77 | V: big.NewInt(25),
78 | S: big.NewInt(26),
79 | R: big.NewInt(27),
80 | }
81 | newTxn := txn.Copy()
82 |
83 | if !reflect.DeepEqual(txn, newTxn) {
84 | t.Fatal("[ERROR] Copied transaction not equal base transaction")
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/validators/ecdsa.go:
--------------------------------------------------------------------------------
1 | package validators
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/types"
5 | "github.com/umbracle/fastrlp"
6 | )
7 |
8 | // BLSValidator is a validator using ECDSA signing algorithm
9 | type ECDSAValidator struct {
10 | Address types.Address
11 | }
12 |
13 | // NewECDSAValidator is a constructor of ECDSAValidator
14 | func NewECDSAValidator(addr types.Address) *ECDSAValidator {
15 | return &ECDSAValidator{
16 | Address: addr,
17 | }
18 | }
19 |
20 | // Type returns the ValidatorType of ECDSAValidator
21 | func (v *ECDSAValidator) Type() ValidatorType {
22 | return ECDSAValidatorType
23 | }
24 |
25 | // String returns string representation of ECDSAValidator
26 | func (v *ECDSAValidator) String() string {
27 | return v.Address.String()
28 | }
29 |
30 | // Addr returns the validator address
31 | func (v *ECDSAValidator) Addr() types.Address {
32 | return v.Address
33 | }
34 |
35 | // Copy returns copy of ECDSAValidator
36 | func (v *ECDSAValidator) Copy() Validator {
37 | return &ECDSAValidator{
38 | Address: v.Address,
39 | }
40 | }
41 |
42 | // Equal checks the given validator matches with its data
43 | func (v *ECDSAValidator) Equal(vr Validator) bool {
44 | vv, ok := vr.(*ECDSAValidator)
45 | if !ok {
46 | return false
47 | }
48 |
49 | return v.Address == vv.Address
50 | }
51 |
52 | // MarshalRLPWith is a RLP Marshaller
53 | func (v *ECDSAValidator) MarshalRLPWith(arena *fastrlp.Arena) *fastrlp.Value {
54 | return arena.NewBytes(v.Address.Bytes())
55 | }
56 |
57 | // UnmarshalRLPFrom is a RLP Unmarshaller
58 | func (v *ECDSAValidator) UnmarshalRLPFrom(p *fastrlp.Parser, val *fastrlp.Value) error {
59 | return val.GetAddr(v.Address[:])
60 | }
61 |
62 | // Bytes returns bytes of ECDSAValidator
63 | func (v *ECDSAValidator) Bytes() []byte {
64 | return v.Address.Bytes()
65 | }
66 |
67 | // SetFromBytes parses given bytes
68 | func (v *ECDSAValidator) SetFromBytes(input []byte) error {
69 | v.Address = types.BytesToAddress(input)
70 |
71 | return nil
72 | }
73 |
--------------------------------------------------------------------------------
/validators/store/snapshot/helper.go:
--------------------------------------------------------------------------------
1 | package snapshot
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/types"
5 | "github.com/ExzoNetwork/ExzoCoin/validators"
6 | )
7 |
8 | // isAuthorize is a helper function to return the bool value from Nonce
9 | func isAuthorize(
10 | nonce types.Nonce,
11 | ) (bool, error) {
12 | switch nonce {
13 | case nonceAuthVote:
14 | return true, nil
15 | case nonceDropVote:
16 | return false, nil
17 | default:
18 | return false, ErrIncorrectNonce
19 | }
20 | }
21 |
22 | // shouldProcessVote is a helper function to return
23 | // the flag indicating whether vote should be processed or not
24 | // based on vote action and validator set
25 | func shouldProcessVote(
26 | validators validators.Validators,
27 | candidate types.Address,
28 | voteAction bool, // true => add, false => remove
29 | ) bool {
30 | // if vote action is...
31 | // true => validator set expects not to have a candidate
32 | // false => validator set expects to have a candidate
33 | return voteAction != validators.Includes(candidate)
34 | }
35 |
36 | // addsOrDelsCandidate is a helper function to add/remove candidate to/from validators
37 | func addsOrDelsCandidate(
38 | validators validators.Validators,
39 | candidate validators.Validator,
40 | updateAction bool,
41 | ) error {
42 | if updateAction {
43 | return validators.Add(candidate)
44 | } else {
45 | return validators.Del(candidate)
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/validators/store/test_helper.go:
--------------------------------------------------------------------------------
1 | package store
2 |
3 | import (
4 | "github.com/ExzoNetwork/ExzoCoin/consensus/ibft/signer"
5 | "github.com/ExzoNetwork/ExzoCoin/types"
6 | )
7 |
8 | // Utilities for test
9 | const (
10 | TestEpochSize = 100
11 | )
12 |
13 | func NewMockGetSigner(s signer.Signer) func(uint64) (signer.Signer, error) {
14 | return func(u uint64) (signer.Signer, error) {
15 | return s, nil
16 | }
17 | }
18 |
19 | type MockBlockchain struct {
20 | HeaderFn func() *types.Header
21 | GetHeaderByNumberFn func(uint64) (*types.Header, bool)
22 | }
23 |
24 | func (m *MockBlockchain) Header() *types.Header {
25 | return m.HeaderFn()
26 | }
27 |
28 | func (m *MockBlockchain) GetHeaderByNumber(height uint64) (*types.Header, bool) {
29 | return m.GetHeaderByNumberFn(height)
30 | }
31 |
--------------------------------------------------------------------------------
/validators/types_test.go:
--------------------------------------------------------------------------------
1 | package validators
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/assert"
7 | )
8 |
9 | func TestParseValidatorType(t *testing.T) {
10 | t.Parallel()
11 |
12 | t.Run("ECDSA", func(t *testing.T) {
13 | t.Parallel()
14 |
15 | res, err := ParseValidatorType("ecdsa")
16 |
17 | assert.Equal(
18 | t,
19 | ECDSAValidatorType,
20 | res,
21 | )
22 |
23 | assert.NoError(
24 | t,
25 | err,
26 | )
27 | })
28 |
29 | t.Run("BLS", func(t *testing.T) {
30 | t.Parallel()
31 |
32 | res, err := ParseValidatorType("bls")
33 |
34 | assert.Equal(
35 | t,
36 | BLSValidatorType,
37 | res,
38 | )
39 |
40 | assert.NoError(
41 | t,
42 | err,
43 | )
44 | })
45 |
46 | t.Run("other type", func(t *testing.T) {
47 | t.Parallel()
48 |
49 | _, err := ParseValidatorType("fake")
50 |
51 | assert.Equal(
52 | t,
53 | ErrInvalidValidatorType,
54 | err,
55 | )
56 | })
57 | }
58 |
--------------------------------------------------------------------------------
/versioning/versioning.go:
--------------------------------------------------------------------------------
1 | package versioning
2 |
3 | var (
4 | // Version is the main version at the moment.
5 | // Commit is the git commit that the binary was built on
6 | // BuildTime is the timestamp of the build
7 | // Embedded by --ldflags on build time
8 | // Versioning should follow the SemVer guidelines
9 | // https://semver.org/
10 | Version string
11 | Branch string
12 | Commit string
13 | BuildTime string
14 | )
15 |
--------------------------------------------------------------------------------