feat: zilliqa consensus data related to block (#10699)
* refactor: DRY declaration of chain type and feature dependent repos * feat: add `:zilliqa` chain type * chore: add `zilliqa` to cspell.json * feat: import consensus data related to block * fix: cspell * fix: ethereum_jsonrpc tests * fix: format & credo * feat: render consensus data in `/api/v2/blocks/:block_hash_or_number` response * fix: add missing `view` field to block db schema * feat: add workflow to publish docker image * fix: cast `zilliqa_view` field of a block * refactor: view * refactor: define spec only once * refactor: DRY definition of other repos * fix: remove not null constraint for `zilliqa_view` * fix: dialyzer * fix: `@spec` for `chain_type_fields/2` * feat: github workflows * fix: debug * fix: add missing indexer and API workflowspull/11144/head
parent
94745592ac
commit
0dfd4c6ca2
@ -0,0 +1,167 @@ |
||||
name: Pre-release for Zilliqa |
||||
|
||||
on: |
||||
workflow_dispatch: |
||||
inputs: |
||||
number: |
||||
type: number |
||||
required: true |
||||
|
||||
env: |
||||
OTP_VERSION: ${{ vars.OTP_VERSION }} |
||||
ELIXIR_VERSION: ${{ vars.ELIXIR_VERSION }} |
||||
|
||||
jobs: |
||||
push_to_registry: |
||||
name: Push Docker image to Docker Hub |
||||
runs-on: ubuntu-latest |
||||
env: |
||||
RELEASE_VERSION: 6.9.0 |
||||
steps: |
||||
- uses: actions/checkout@v4 |
||||
- name: Setup repo |
||||
uses: ./.github/actions/setup-repo |
||||
id: setup |
||||
with: |
||||
docker-username: ${{ secrets.DOCKER_USERNAME }} |
||||
docker-password: ${{ secrets.DOCKER_PASSWORD }} |
||||
docker-remote-multi-platform: true |
||||
docker-arm-host: ${{ secrets.ARM_RUNNER_HOSTNAME }} |
||||
docker-arm-host-key: ${{ secrets.ARM_RUNNER_KEY }} |
||||
|
||||
- name: Build and push Docker image (indexer + API) |
||||
uses: docker/build-push-action@v5 |
||||
with: |
||||
context: . |
||||
file: ./docker/Dockerfile |
||||
push: true |
||||
tags: blockscout/blockscout-zilliqa:${{ env.RELEASE_VERSION }}-alpha.${{ inputs.number }} |
||||
labels: ${{ steps.setup.outputs.docker-labels }} |
||||
platforms: | |
||||
linux/amd64 |
||||
linux/arm64/v8 |
||||
build-args: | |
||||
DISABLE_WEBAPP=false |
||||
API_V1_READ_METHODS_DISABLED=false |
||||
API_V1_WRITE_METHODS_DISABLED=false |
||||
CACHE_EXCHANGE_RATES_PERIOD= |
||||
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= |
||||
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= |
||||
ADMIN_PANEL_ENABLED=false |
||||
BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-alpha.${{ inputs.number }} |
||||
RELEASE_VERSION=${{ env.RELEASE_VERSION }} |
||||
CHAIN_TYPE=zilliqa |
||||
|
||||
- name: Build and push Docker image (indexer) |
||||
uses: docker/build-push-action@v5 |
||||
with: |
||||
context: . |
||||
file: ./docker/Dockerfile |
||||
push: true |
||||
tags: blockscout/blockscout-zilliqa:${{ env.RELEASE_VERSION }}-alpha.${{ inputs.number }}-indexer |
||||
labels: ${{ steps.setup.outputs.docker-labels }} |
||||
platforms: | |
||||
linux/amd64 |
||||
linux/arm64/v8 |
||||
build-args: | |
||||
DISABLE_API=true |
||||
DISABLE_WEBAPP=true |
||||
CACHE_EXCHANGE_RATES_PERIOD= |
||||
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= |
||||
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= |
||||
ADMIN_PANEL_ENABLED=false |
||||
BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-alpha.${{ inputs.number }} |
||||
RELEASE_VERSION=${{ env.RELEASE_VERSION }} |
||||
CHAIN_TYPE=zilliqa |
||||
|
||||
- name: Build and push Docker image (API) |
||||
uses: docker/build-push-action@v5 |
||||
with: |
||||
context: . |
||||
file: ./docker/Dockerfile |
||||
push: true |
||||
tags: blockscout/blockscout-zilliqa:${{ env.RELEASE_VERSION }}-alpha.${{ inputs.number }}-api |
||||
labels: ${{ steps.setup.outputs.docker-labels }} |
||||
platforms: | |
||||
linux/amd64 |
||||
linux/arm64/v8 |
||||
build-args: | |
||||
DISABLE_INDEXER=true |
||||
DISABLE_WEBAPP=true |
||||
CACHE_EXCHANGE_RATES_PERIOD= |
||||
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= |
||||
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= |
||||
ADMIN_PANEL_ENABLED=false |
||||
BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-alpha.${{ inputs.number }} |
||||
RELEASE_VERSION=${{ env.RELEASE_VERSION }} |
||||
CHAIN_TYPE=zilliqa |
||||
|
||||
- name: Build and push Docker image (indexer + API + shrink internal transactions) |
||||
uses: docker/build-push-action@v5 |
||||
with: |
||||
context: . |
||||
file: ./docker/Dockerfile |
||||
push: true |
||||
tags: blockscout/blockscout-zilliqa:${{ env.RELEASE_VERSION }}-alpha.${{ inputs.number }}-shrink-internal-txs |
||||
labels: ${{ steps.setup.outputs.docker-labels }} |
||||
platforms: | |
||||
linux/amd64 |
||||
linux/arm64/v8 |
||||
build-args: | |
||||
CACHE_EXCHANGE_RATES_PERIOD= |
||||
API_V1_READ_METHODS_DISABLED=false |
||||
DISABLE_WEBAPP=false |
||||
API_V1_WRITE_METHODS_DISABLED=false |
||||
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= |
||||
ADMIN_PANEL_ENABLED=false |
||||
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= |
||||
BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-alpha.${{ inputs.number }} |
||||
RELEASE_VERSION=${{ env.RELEASE_VERSION }} |
||||
CHAIN_TYPE=zilliqa |
||||
SHRINK_INTERNAL_TRANSACTIONS_ENABLED=true |
||||
|
||||
- name: Build and push Docker image (indexer + shrink internal transactions) |
||||
uses: docker/build-push-action@v5 |
||||
with: |
||||
context: . |
||||
file: ./docker/Dockerfile |
||||
push: true |
||||
tags: blockscout/blockscout-zilliqa:${{ env.RELEASE_VERSION }}-alpha.${{ inputs.number }}-shrink-internal-txs-indexer |
||||
labels: ${{ steps.setup.outputs.docker-labels }} |
||||
platforms: | |
||||
linux/amd64 |
||||
linux/arm64/v8 |
||||
build-args: | |
||||
CACHE_EXCHANGE_RATES_PERIOD= |
||||
DISABLE_WEBAPP=true |
||||
DISABLE_API=true |
||||
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= |
||||
ADMIN_PANEL_ENABLED=false |
||||
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= |
||||
BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-alpha.${{ inputs.number }} |
||||
RELEASE_VERSION=${{ env.RELEASE_VERSION }} |
||||
CHAIN_TYPE=zilliqa |
||||
SHRINK_INTERNAL_TRANSACTIONS_ENABLED=true |
||||
|
||||
- name: Build and push Docker image (API + shrink internal transactions) |
||||
uses: docker/build-push-action@v5 |
||||
with: |
||||
context: . |
||||
file: ./docker/Dockerfile |
||||
push: true |
||||
tags: blockscout/blockscout-zilliqa:${{ env.RELEASE_VERSION }}-alpha.${{ inputs.number }}-shrink-internal-txs-api |
||||
labels: ${{ steps.setup.outputs.docker-labels }} |
||||
platforms: | |
||||
linux/amd64 |
||||
linux/arm64/v8 |
||||
build-args: | |
||||
CACHE_EXCHANGE_RATES_PERIOD= |
||||
DISABLE_WEBAPP=true |
||||
DISABLE_INDEXER=true |
||||
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= |
||||
ADMIN_PANEL_ENABLED=false |
||||
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= |
||||
BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-alpha.${{ inputs.number }} |
||||
RELEASE_VERSION=${{ env.RELEASE_VERSION }} |
||||
CHAIN_TYPE=zilliqa |
||||
SHRINK_INTERNAL_TRANSACTIONS_ENABLED=true |
@ -0,0 +1,162 @@ |
||||
name: Zilliqa publish Docker image |
||||
|
||||
on: |
||||
workflow_dispatch: |
||||
push: |
||||
branches: |
||||
- production-zilliqa |
||||
jobs: |
||||
push_to_registry: |
||||
name: Push Docker image to Docker Hub |
||||
runs-on: ubuntu-latest |
||||
env: |
||||
RELEASE_VERSION: 6.9.0 |
||||
DOCKER_CHAIN_NAME: zilliqa |
||||
steps: |
||||
- uses: actions/checkout@v4 |
||||
- name: Setup repo |
||||
uses: ./.github/actions/setup-repo |
||||
id: setup |
||||
with: |
||||
docker-username: ${{ secrets.DOCKER_USERNAME }} |
||||
docker-password: ${{ secrets.DOCKER_PASSWORD }} |
||||
docker-remote-multi-platform: true |
||||
docker-arm-host: ${{ secrets.ARM_RUNNER_HOSTNAME }} |
||||
docker-arm-host-key: ${{ secrets.ARM_RUNNER_KEY }} |
||||
|
||||
- name: Build and push Docker image (indexer + API) |
||||
uses: docker/build-push-action@v5 |
||||
with: |
||||
context: . |
||||
file: ./docker/Dockerfile |
||||
push: true |
||||
tags: blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:${{ env.RELEASE_VERSION }}-postrelease-${{ env.SHORT_SHA }} |
||||
labels: ${{ steps.setup.outputs.docker-labels }} |
||||
platforms: | |
||||
linux/amd64 |
||||
linux/arm64/v8 |
||||
build-args: | |
||||
CACHE_EXCHANGE_RATES_PERIOD= |
||||
API_V1_READ_METHODS_DISABLED=false |
||||
DISABLE_WEBAPP=false |
||||
API_V1_WRITE_METHODS_DISABLED=false |
||||
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= |
||||
ADMIN_PANEL_ENABLED=false |
||||
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= |
||||
BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta.+commit.${{ env.SHORT_SHA }} |
||||
RELEASE_VERSION=${{ env.RELEASE_VERSION }} |
||||
CHAIN_TYPE=${{ env.DOCKER_CHAIN_NAME }} |
||||
|
||||
- name: Build and push Docker image (indexer) |
||||
uses: docker/build-push-action@v5 |
||||
with: |
||||
context: . |
||||
file: ./docker/Dockerfile |
||||
push: true |
||||
tags: blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:${{ env.RELEASE_VERSION }}-postrelease-${{ env.SHORT_SHA }}-indexer |
||||
labels: ${{ steps.setup.outputs.docker-labels }} |
||||
platforms: | |
||||
linux/amd64 |
||||
linux/arm64/v8 |
||||
build-args: | |
||||
CACHE_EXCHANGE_RATES_PERIOD= |
||||
DISABLE_WEBAPP=true |
||||
DISABLE_API=true |
||||
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= |
||||
ADMIN_PANEL_ENABLED=false |
||||
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= |
||||
BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta.+commit.${{ env.SHORT_SHA }} |
||||
RELEASE_VERSION=${{ env.RELEASE_VERSION }} |
||||
CHAIN_TYPE=${{ env.DOCKER_CHAIN_NAME }} |
||||
|
||||
- name: Build and push Docker image (API) |
||||
uses: docker/build-push-action@v5 |
||||
with: |
||||
context: . |
||||
file: ./docker/Dockerfile |
||||
push: true |
||||
tags: blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:${{ env.RELEASE_VERSION }}-postrelease-${{ env.SHORT_SHA }}-api |
||||
labels: ${{ steps.setup.outputs.docker-labels }} |
||||
platforms: | |
||||
linux/amd64 |
||||
linux/arm64/v8 |
||||
build-args: | |
||||
CACHE_EXCHANGE_RATES_PERIOD= |
||||
DISABLE_WEBAPP=true |
||||
DISABLE_INDEXER=true |
||||
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= |
||||
ADMIN_PANEL_ENABLED=false |
||||
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= |
||||
BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta.+commit.${{ env.SHORT_SHA }} |
||||
RELEASE_VERSION=${{ env.RELEASE_VERSION }} |
||||
CHAIN_TYPE=${{ env.DOCKER_CHAIN_NAME }} |
||||
|
||||
- name: Build and push Docker image (indexer + API + shrink internal transactions) |
||||
uses: docker/build-push-action@v5 |
||||
with: |
||||
context: . |
||||
file: ./docker/Dockerfile |
||||
push: true |
||||
tags: blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:${{ env.RELEASE_VERSION }}-postrelease-${{ env.SHORT_SHA }}-shrink-internal-txs |
||||
labels: ${{ steps.setup.outputs.docker-labels }} |
||||
platforms: | |
||||
linux/amd64 |
||||
linux/arm64/v8 |
||||
build-args: | |
||||
CACHE_EXCHANGE_RATES_PERIOD= |
||||
API_V1_READ_METHODS_DISABLED=false |
||||
DISABLE_WEBAPP=false |
||||
API_V1_WRITE_METHODS_DISABLED=false |
||||
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= |
||||
ADMIN_PANEL_ENABLED=false |
||||
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= |
||||
BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta.+commit.${{ env.SHORT_SHA }} |
||||
RELEASE_VERSION=${{ env.RELEASE_VERSION }} |
||||
CHAIN_TYPE=${{ env.DOCKER_CHAIN_NAME }} |
||||
SHRINK_INTERNAL_TRANSACTIONS_ENABLED=true |
||||
|
||||
- name: Build and push Docker image (indexer + shrink internal transactions) |
||||
uses: docker/build-push-action@v5 |
||||
with: |
||||
context: . |
||||
file: ./docker/Dockerfile |
||||
push: true |
||||
tags: blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:${{ env.RELEASE_VERSION }}-postrelease-${{ env.SHORT_SHA }}-shrink-internal-txs-indexer |
||||
labels: ${{ steps.setup.outputs.docker-labels }} |
||||
platforms: | |
||||
linux/amd64 |
||||
linux/arm64/v8 |
||||
build-args: | |
||||
CACHE_EXCHANGE_RATES_PERIOD= |
||||
DISABLE_WEBAPP=true |
||||
DISABLE_API=true |
||||
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= |
||||
ADMIN_PANEL_ENABLED=false |
||||
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= |
||||
BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta.+commit.${{ env.SHORT_SHA }} |
||||
RELEASE_VERSION=${{ env.RELEASE_VERSION }} |
||||
CHAIN_TYPE=${{ env.DOCKER_CHAIN_NAME }} |
||||
SHRINK_INTERNAL_TRANSACTIONS_ENABLED=true |
||||
|
||||
- name: Build and push Docker image (API + shrink internal transactions) |
||||
uses: docker/build-push-action@v5 |
||||
with: |
||||
context: . |
||||
file: ./docker/Dockerfile |
||||
push: true |
||||
tags: blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:${{ env.RELEASE_VERSION }}-postrelease-${{ env.SHORT_SHA }}-shrink-internal-txs-api |
||||
labels: ${{ steps.setup.outputs.docker-labels }} |
||||
platforms: | |
||||
linux/amd64 |
||||
linux/arm64/v8 |
||||
build-args: | |
||||
CACHE_EXCHANGE_RATES_PERIOD= |
||||
DISABLE_WEBAPP=true |
||||
DISABLE_INDEXER=true |
||||
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= |
||||
ADMIN_PANEL_ENABLED=false |
||||
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= |
||||
BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta.+commit.${{ env.SHORT_SHA }} |
||||
RELEASE_VERSION=${{ env.RELEASE_VERSION }} |
||||
CHAIN_TYPE=${{ env.DOCKER_CHAIN_NAME }} |
||||
SHRINK_INTERNAL_TRANSACTIONS_ENABLED=true |
@ -0,0 +1,164 @@ |
||||
name: Release for Zilliqa |
||||
|
||||
on: |
||||
release: |
||||
types: [published] |
||||
|
||||
env: |
||||
OTP_VERSION: ${{ vars.OTP_VERSION }} |
||||
ELIXIR_VERSION: ${{ vars.ELIXIR_VERSION }} |
||||
|
||||
jobs: |
||||
push_to_registry: |
||||
name: Push Docker image to Docker Hub |
||||
runs-on: ubuntu-latest |
||||
env: |
||||
RELEASE_VERSION: 6.9.0 |
||||
steps: |
||||
- uses: actions/checkout@v4 |
||||
- name: Setup repo |
||||
uses: ./.github/actions/setup-repo |
||||
id: setup |
||||
with: |
||||
docker-username: ${{ secrets.DOCKER_USERNAME }} |
||||
docker-password: ${{ secrets.DOCKER_PASSWORD }} |
||||
docker-remote-multi-platform: true |
||||
docker-arm-host: ${{ secrets.ARM_RUNNER_HOSTNAME }} |
||||
docker-arm-host-key: ${{ secrets.ARM_RUNNER_KEY }} |
||||
|
||||
- name: Build and push Docker image (indexer + API) |
||||
uses: docker/build-push-action@v5 |
||||
with: |
||||
context: . |
||||
file: ./docker/Dockerfile |
||||
push: true |
||||
tags: blockscout/blockscout-zilliqa:latest, blockscout/blockscout-zilliqa:${{ env.RELEASE_VERSION }} |
||||
labels: ${{ steps.setup.outputs.docker-labels }} |
||||
platforms: | |
||||
linux/amd64 |
||||
linux/arm64/v8 |
||||
build-args: | |
||||
DISABLE_WEBAPP=false |
||||
API_V1_READ_METHODS_DISABLED=false |
||||
API_V1_WRITE_METHODS_DISABLED=false |
||||
CACHE_EXCHANGE_RATES_PERIOD= |
||||
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= |
||||
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= |
||||
ADMIN_PANEL_ENABLED=false |
||||
BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta |
||||
RELEASE_VERSION=${{ env.RELEASE_VERSION }} |
||||
CHAIN_TYPE=zilliqa |
||||
|
||||
- name: Build and push Docker image (indexer) |
||||
uses: docker/build-push-action@v5 |
||||
with: |
||||
context: . |
||||
file: ./docker/Dockerfile |
||||
push: true |
||||
tags: blockscout/blockscout-zilliqa:${{ env.RELEASE_VERSION }}-indexer |
||||
labels: ${{ steps.setup.outputs.docker-labels }} |
||||
platforms: | |
||||
linux/amd64 |
||||
linux/arm64/v8 |
||||
build-args: | |
||||
DISABLE_API=true |
||||
DISABLE_WEBAPP=true |
||||
CACHE_EXCHANGE_RATES_PERIOD= |
||||
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= |
||||
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= |
||||
ADMIN_PANEL_ENABLED=false |
||||
BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta |
||||
RELEASE_VERSION=${{ env.RELEASE_VERSION }} |
||||
CHAIN_TYPE=zilliqa |
||||
|
||||
- name: Build and push Docker image (API) |
||||
uses: docker/build-push-action@v5 |
||||
with: |
||||
context: . |
||||
file: ./docker/Dockerfile |
||||
push: true |
||||
tags: blockscout/blockscout-zilliqa:${{ env.RELEASE_VERSION }}-api |
||||
labels: ${{ steps.setup.outputs.docker-labels }} |
||||
platforms: | |
||||
linux/amd64 |
||||
linux/arm64/v8 |
||||
build-args: | |
||||
DISABLE_INDEXER=true |
||||
DISABLE_WEBAPP=true |
||||
CACHE_EXCHANGE_RATES_PERIOD= |
||||
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= |
||||
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= |
||||
ADMIN_PANEL_ENABLED=false |
||||
BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta |
||||
RELEASE_VERSION=${{ env.RELEASE_VERSION }} |
||||
CHAIN_TYPE=zilliqa |
||||
|
||||
- name: Build and push Docker image (indexer + API + shrink internal transactions) |
||||
uses: docker/build-push-action@v5 |
||||
with: |
||||
context: . |
||||
file: ./docker/Dockerfile |
||||
push: true |
||||
tags: blockscout/blockscout-zilliqa:${{ env.RELEASE_VERSION }}-shrink-internal-txs |
||||
labels: ${{ steps.setup.outputs.docker-labels }} |
||||
platforms: | |
||||
linux/amd64 |
||||
linux/arm64/v8 |
||||
build-args: | |
||||
CACHE_EXCHANGE_RATES_PERIOD= |
||||
API_V1_READ_METHODS_DISABLED=false |
||||
DISABLE_WEBAPP=false |
||||
API_V1_WRITE_METHODS_DISABLED=false |
||||
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= |
||||
ADMIN_PANEL_ENABLED=false |
||||
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= |
||||
BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta |
||||
RELEASE_VERSION=${{ env.RELEASE_VERSION }} |
||||
CHAIN_TYPE=zilliqa |
||||
SHRINK_INTERNAL_TRANSACTIONS_ENABLED=true |
||||
|
||||
- name: Build and push Docker image (indexer + shrink internal transactions) |
||||
uses: docker/build-push-action@v5 |
||||
with: |
||||
context: . |
||||
file: ./docker/Dockerfile |
||||
push: true |
||||
tags: blockscout/blockscout-zilliqa:${{ env.RELEASE_VERSION }}-shrink-internal-txs-indexer |
||||
labels: ${{ steps.setup.outputs.docker-labels }} |
||||
platforms: | |
||||
linux/amd64 |
||||
linux/arm64/v8 |
||||
build-args: | |
||||
CACHE_EXCHANGE_RATES_PERIOD= |
||||
DISABLE_WEBAPP=true |
||||
DISABLE_API=true |
||||
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= |
||||
ADMIN_PANEL_ENABLED=false |
||||
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= |
||||
BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta |
||||
RELEASE_VERSION=${{ env.RELEASE_VERSION }} |
||||
CHAIN_TYPE=zilliqa |
||||
SHRINK_INTERNAL_TRANSACTIONS_ENABLED=true |
||||
|
||||
- name: Build and push Docker image (API + shrink internal transactions) |
||||
uses: docker/build-push-action@v5 |
||||
with: |
||||
context: . |
||||
file: ./docker/Dockerfile |
||||
push: true |
||||
tags: blockscout/blockscout-zilliqa:${{ env.RELEASE_VERSION }}-shrink-internal-txs-api |
||||
labels: ${{ steps.setup.outputs.docker-labels }} |
||||
platforms: | |
||||
linux/amd64 |
||||
linux/arm64/v8 |
||||
build-args: | |
||||
CACHE_EXCHANGE_RATES_PERIOD= |
||||
DISABLE_WEBAPP=true |
||||
DISABLE_INDEXER=true |
||||
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= |
||||
ADMIN_PANEL_ENABLED=false |
||||
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= |
||||
BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta |
||||
RELEASE_VERSION=${{ env.RELEASE_VERSION }} |
||||
CHAIN_TYPE=zilliqa |
||||
SHRINK_INTERNAL_TRANSACTIONS_ENABLED=true |
@ -0,0 +1,88 @@ |
||||
if Application.compile_env(:explorer, :chain_type) == :zilliqa do |
||||
defmodule BlockScoutWeb.API.V2.ZilliqaView do |
||||
@moduledoc """ |
||||
View functions for rendering Zilliqa-related data in JSON format. |
||||
""" |
||||
|
||||
alias Explorer.Chain.Block |
||||
alias Explorer.Chain.Zilliqa.{AggregateQuorumCertificate, QuorumCertificate} |
||||
|
||||
@doc """ |
||||
Extends the JSON output with a sub-map containing information related to Zilliqa, |
||||
such as the quorum certificate and aggregate quorum certificate. |
||||
|
||||
## Parameters |
||||
- `out_json`: A map defining the output JSON which will be extended. |
||||
- `block`: The block structure containing Zilliqa-related data. |
||||
- `single_block?`: A boolean indicating if it is a single block. |
||||
|
||||
## Returns |
||||
- A map extended with data related to Zilliqa. |
||||
""" |
||||
@spec extend_block_json_response(map(), Block.t(), boolean()) :: map() |
||||
def extend_block_json_response(out_json, %Block{}, false), |
||||
do: out_json |
||||
|
||||
def extend_block_json_response(out_json, %Block{zilliqa_view: zilliqa_view} = block, true) do |
||||
zilliqa_json = |
||||
%{view: zilliqa_view} |
||||
|> add_quorum_certificate(block) |
||||
|> add_aggregate_quorum_certificate(block) |
||||
|
||||
Map.put(out_json, :zilliqa, zilliqa_json) |
||||
end |
||||
|
||||
@spec add_quorum_certificate(map(), Block.t()) :: map() |
||||
defp add_quorum_certificate( |
||||
zilliqa_json, |
||||
%Block{ |
||||
zilliqa_quorum_certificate: %QuorumCertificate{ |
||||
view: view, |
||||
signature: signature, |
||||
signers: signers |
||||
} |
||||
} |
||||
) do |
||||
zilliqa_json |
||||
|> Map.put(:quorum_certificate, %{ |
||||
view: view, |
||||
signature: signature, |
||||
signers: signers |
||||
}) |
||||
end |
||||
|
||||
defp add_quorum_certificate(zilliqa_json, _block), do: zilliqa_json |
||||
|
||||
@spec add_aggregate_quorum_certificate(map(), Block.t()) :: map() |
||||
defp add_aggregate_quorum_certificate(zilliqa_json, %Block{ |
||||
zilliqa_aggregate_quorum_certificate: %AggregateQuorumCertificate{ |
||||
view: view, |
||||
signature: signature, |
||||
nested_quorum_certificates: nested_quorum_certificates |
||||
} |
||||
}) |
||||
when is_list(nested_quorum_certificates) do |
||||
zilliqa_json |
||||
|> Map.put(:aggregate_quorum_certificate, %{ |
||||
view: view, |
||||
signature: signature, |
||||
signers: |
||||
Enum.map( |
||||
nested_quorum_certificates, |
||||
& &1.proposed_by_validator_index |
||||
), |
||||
nested_quorum_certificates: |
||||
Enum.map( |
||||
nested_quorum_certificates, |
||||
&%{ |
||||
view: &1.view, |
||||
signature: &1.signature, |
||||
proposed_by_validator_index: &1.proposed_by_validator_index |
||||
} |
||||
) |
||||
}) |
||||
end |
||||
|
||||
defp add_aggregate_quorum_certificate(zilliqa_json, _block), do: zilliqa_json |
||||
end |
||||
end |
@ -0,0 +1,20 @@ |
||||
defmodule EthereumJSONRPC.Zilliqa do |
||||
@moduledoc """ |
||||
Zilliqa type definitions. |
||||
""" |
||||
alias EthereumJSONRPC.Zilliqa.{ |
||||
AggregateQuorumCertificate, |
||||
NestedQuorumCertificates, |
||||
QuorumCertificate |
||||
} |
||||
|
||||
@type consensus_data_params :: %{ |
||||
zilliqa_quorum_certificates_params: [QuorumCertificate.params()], |
||||
zilliqa_aggregate_quorum_certificates_params: [AggregateQuorumCertificate.params()], |
||||
zilliqa_nested_quorum_certificates_params: [NestedQuorumCertificates.params()] |
||||
} |
||||
|
||||
@type bit_vector :: String.t() |
||||
@type validator_index :: non_neg_integer() |
||||
@type signers :: [validator_index()] |
||||
end |
@ -0,0 +1,186 @@ |
||||
defmodule EthereumJSONRPC.Zilliqa.AggregateQuorumCertificate do |
||||
@moduledoc """ |
||||
Represents an aggregate quorum certificate associated with the block. |
||||
""" |
||||
import EthereumJSONRPC, only: [quantity_to_integer: 1] |
||||
|
||||
alias EthereumJSONRPC.Zilliqa.NestedQuorumCertificates |
||||
|
||||
@type elixir :: %{ |
||||
String.t() => |
||||
EthereumJSONRPC.quantity() |
||||
| EthereumJSONRPC.hash() |
||||
| EthereumJSONRPC.Zilliqa.bit_vector() |
||||
| NestedQuorumCertificates.elixir() |
||||
} |
||||
|
||||
@type t :: %__MODULE__{ |
||||
block_hash: EthereumJSONRPC.hash(), |
||||
view: non_neg_integer(), |
||||
signature: EthereumJSONRPC.hash(), |
||||
quorum_certificates: NestedQuorumCertificates.t() |
||||
} |
||||
|
||||
@type params :: %{ |
||||
block_hash: EthereumJSONRPC.hash(), |
||||
view: non_neg_integer(), |
||||
signature: EthereumJSONRPC.hash() |
||||
} |
||||
|
||||
defstruct [:block_hash, :view, :signature, :quorum_certificates] |
||||
|
||||
@doc """ |
||||
Decodes the JSON object returned by JSONRPC node into the `t:t/0` format. |
||||
|
||||
## Examples |
||||
|
||||
iex> aqc_json = %{ |
||||
...> "cosigned" => "[0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", |
||||
...> "quorum_certificates" => [ |
||||
...> %{ |
||||
...> "block_hash" => "0x4b8939a7fb0d7de4b288bafd4d5caa02f53abf3c1e348fca5038eebbf68248fa", |
||||
...> "cosigned" => "[1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", |
||||
...> "signature" => "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
...> "view" => "0x115cc7" |
||||
...> }, |
||||
...> %{ |
||||
...> "block_hash" => "0x4b8939a7fb0d7de4b288bafd4d5caa02f53abf3c1e348fca5038eebbf68248fa", |
||||
...> "cosigned" => "[1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", |
||||
...> "signature" => "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
...> "view" => "0x115cc7" |
||||
...> }, |
||||
...> %{ |
||||
...> "block_hash" => "0x4b8939a7fb0d7de4b288bafd4d5caa02f53abf3c1e348fca5038eebbf68248fa", |
||||
...> "cosigned" => "[1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", |
||||
...> "signature" => "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
...> "view" => "0x115cc7" |
||||
...> }, |
||||
...> %{ |
||||
...> "block_hash" => "0x4b8939a7fb0d7de4b288bafd4d5caa02f53abf3c1e348fca5038eebbf68248fa", |
||||
...> "cosigned" => "[1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", |
||||
...> "signature" => "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
...> "view" => "0x115cc7" |
||||
...> } |
||||
...> ], |
||||
...> "signature" => "0x820f591cd78b29a69ba25bc85c4327fa3b0adb61a73a4f0bd943b4ab0b97e061eae9ac032d19fbfab7efb89fac2454ab0b89fea83185c0dac749ff55b0e2c21535a2b712872491577728db868d11939461a6bfde0d94d238f46b643bbe19767e", |
||||
...> "view" => "0x115cca" |
||||
...> } |
||||
iex> block_hash = "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d" |
||||
iex> EthereumJSONRPC.Zilliqa.AggregateQuorumCertificate.new(aqc_json, block_hash) |
||||
%EthereumJSONRPC.Zilliqa.AggregateQuorumCertificate{ |
||||
block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
view: 1137866, |
||||
signature: "0x820f591cd78b29a69ba25bc85c4327fa3b0adb61a73a4f0bd943b4ab0b97e061eae9ac032d19fbfab7efb89fac2454ab0b89fea83185c0dac749ff55b0e2c21535a2b712872491577728db868d11939461a6bfde0d94d238f46b643bbe19767e", |
||||
quorum_certificates: %EthereumJSONRPC.Zilliqa.NestedQuorumCertificates{ |
||||
signers: [1, 2, 3, 8], |
||||
items: [ |
||||
%EthereumJSONRPC.Zilliqa.QuorumCertificate{ |
||||
block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
view: 1137863, |
||||
signature: "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
signers: [0, 1, 3, 8] |
||||
}, |
||||
%EthereumJSONRPC.Zilliqa.QuorumCertificate{ |
||||
block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
view: 1137863, |
||||
signature: "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
signers: [0, 1, 3, 8] |
||||
}, |
||||
%EthereumJSONRPC.Zilliqa.QuorumCertificate{ |
||||
block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
view: 1137863, |
||||
signature: "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
signers: [0, 1, 3, 8] |
||||
}, |
||||
%EthereumJSONRPC.Zilliqa.QuorumCertificate{ |
||||
block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
view: 1137863, |
||||
signature: "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
signers: [0, 1, 3, 8] |
||||
} |
||||
] |
||||
} |
||||
} |
||||
""" |
||||
@spec new(elixir(), EthereumJSONRPC.hash()) :: t() |
||||
def new( |
||||
%{ |
||||
"view" => view, |
||||
"signature" => signature, |
||||
"cosigned" => bit_vector, |
||||
"quorum_certificates" => quorum_certificates |
||||
}, |
||||
block_hash |
||||
) do |
||||
%__MODULE__{ |
||||
block_hash: block_hash, |
||||
view: quantity_to_integer(view), |
||||
signature: signature, |
||||
quorum_certificates: |
||||
NestedQuorumCertificates.new( |
||||
quorum_certificates, |
||||
bit_vector, |
||||
block_hash |
||||
) |
||||
} |
||||
end |
||||
|
||||
@doc """ |
||||
Converts `t:t/0` format to params used in `Explorer.Chain`. |
||||
|
||||
## Examples |
||||
|
||||
iex> aggregate_quorum_certificate = %EthereumJSONRPC.Zilliqa.AggregateQuorumCertificate{ |
||||
...> block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
...> view: 1137866, |
||||
...> signature: "0x820f591cd78b29a69ba25bc85c4327fa3b0adb61a73a4f0bd943b4ab0b97e061eae9ac032d19fbfab7efb89fac2454ab0b89fea83185c0dac749ff55b0e2c21535a2b712872491577728db868d11939461a6bfde0d94d238f46b643bbe19767e", |
||||
...> quorum_certificates: %EthereumJSONRPC.Zilliqa.NestedQuorumCertificates{ |
||||
...> signers: [1, 2, 3, 8], |
||||
...> items: [ |
||||
...> %EthereumJSONRPC.Zilliqa.QuorumCertificate{ |
||||
...> block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
...> view: 1137863, |
||||
...> signature: "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
...> signers: [0, 1, 3, 8] |
||||
...> }, |
||||
...> %EthereumJSONRPC.Zilliqa.QuorumCertificate{ |
||||
...> block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
...> view: 1137863, |
||||
...> signature: "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
...> signers: [0, 1, 3, 8] |
||||
...> }, |
||||
...> %EthereumJSONRPC.Zilliqa.QuorumCertificate{ |
||||
...> block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
...> view: 1137863, |
||||
...> signature: "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
...> signers: [0, 1, 3, 8] |
||||
...> }, |
||||
...> %EthereumJSONRPC.Zilliqa.QuorumCertificate{ |
||||
...> block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
...> view: 1137863, |
||||
...> signature: "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
...> signers: [0, 1, 3, 8] |
||||
...> } |
||||
...> ] |
||||
...> } |
||||
...> } |
||||
iex> EthereumJSONRPC.Zilliqa.AggregateQuorumCertificate.to_params(aggregate_quorum_certificate) |
||||
%{ |
||||
signature: "0x820f591cd78b29a69ba25bc85c4327fa3b0adb61a73a4f0bd943b4ab0b97e061eae9ac032d19fbfab7efb89fac2454ab0b89fea83185c0dac749ff55b0e2c21535a2b712872491577728db868d11939461a6bfde0d94d238f46b643bbe19767e", |
||||
block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
view: 1137866 |
||||
} |
||||
""" |
||||
@spec to_params(t()) :: params() |
||||
def to_params(%__MODULE__{ |
||||
block_hash: block_hash, |
||||
view: view, |
||||
signature: signature |
||||
}) do |
||||
%{ |
||||
block_hash: block_hash, |
||||
view: view, |
||||
signature: signature |
||||
} |
||||
end |
||||
end |
@ -0,0 +1,111 @@ |
||||
defmodule EthereumJSONRPC.Zilliqa.Helper do |
||||
@moduledoc """ |
||||
Helper functions for processing consensus data. |
||||
""" |
||||
alias EthereumJSONRPC.Zilliqa |
||||
alias EthereumJSONRPC.{Block, Blocks} |
||||
|
||||
alias EthereumJSONRPC.Zilliqa.{ |
||||
AggregateQuorumCertificate, |
||||
NestedQuorumCertificates, |
||||
QuorumCertificate |
||||
} |
||||
|
||||
@initial_acc %{ |
||||
zilliqa_quorum_certificates_params: [], |
||||
zilliqa_aggregate_quorum_certificates_params: [], |
||||
zilliqa_nested_quorum_certificates_params: [] |
||||
} |
||||
|
||||
@type consensus_data_params :: %{ |
||||
zilliqa_quorum_certificates_params: [QuorumCertificate.params()], |
||||
zilliqa_aggregate_quorum_certificates_params: [AggregateQuorumCertificate.params()], |
||||
zilliqa_nested_quorum_certificates_params: [NestedQuorumCertificates.params()] |
||||
} |
||||
|
||||
@spec extend_blocks_struct(Blocks.t(), Blocks.elixir()) :: Blocks.t() |
||||
def extend_blocks_struct(%Blocks{} = module, elixir_blocks) do |
||||
consensus_data_fields = |
||||
Enum.reduce( |
||||
elixir_blocks, |
||||
@initial_acc, |
||||
&reduce_to_consensus_data/2 |
||||
) |
||||
|
||||
Map.merge(module, consensus_data_fields) |
||||
end |
||||
|
||||
@doc """ |
||||
Converts a bit vector string to a list of indexes where the bit corresponding |
||||
to signing validator is 1. |
||||
|
||||
## Examples |
||||
|
||||
iex> bit_vector_to_signers("[1, 0, 1, 0]") |
||||
[0, 2] |
||||
|
||||
iex> bit_vector_to_signers("[1, 1, 1, 1]") |
||||
[0, 1, 2, 3] |
||||
""" |
||||
@spec bit_vector_to_signers(Zilliqa.bit_vector()) :: Zilliqa.signers() |
||||
def bit_vector_to_signers(bit_vector_string) do |
||||
bit_vector_string |
||||
|> Jason.decode!() |
||||
|> Enum.with_index() |
||||
|> Enum.filter(fn {bit, _} -> bit == 1 end) |
||||
|> Enum.map(fn {_, index} -> index end) |
||||
end |
||||
|
||||
@spec reduce_to_consensus_data( |
||||
Block.elixir(), |
||||
consensus_data_params() |
||||
) :: consensus_data_params() |
||||
defp reduce_to_consensus_data( |
||||
elixir_block, |
||||
%{ |
||||
zilliqa_quorum_certificates_params: quorum_certificates_params_acc, |
||||
zilliqa_aggregate_quorum_certificates_params: aggregate_quorum_certificates_params_acc, |
||||
zilliqa_nested_quorum_certificates_params: aggregate_nested_quorum_certificates_params_acc |
||||
} |
||||
) do |
||||
quorum_certificates_map = |
||||
elixir_block |
||||
|> Block.elixir_to_zilliqa_quorum_certificate() |
||||
|> case do |
||||
nil -> |
||||
%{zilliqa_quorum_certificates_params: quorum_certificates_params_acc} |
||||
|
||||
quorum_certificate -> |
||||
quorum_certificate_params = QuorumCertificate.to_params(quorum_certificate) |
||||
%{zilliqa_quorum_certificates_params: [quorum_certificate_params | quorum_certificates_params_acc]} |
||||
end |
||||
|
||||
aggregated_quorum_certificate_map = |
||||
elixir_block |
||||
|> Block.elixir_to_zilliqa_aggregate_quorum_certificate() |
||||
|> case do |
||||
nil -> |
||||
%{ |
||||
zilliqa_aggregate_quorum_certificates_params: aggregate_quorum_certificates_params_acc, |
||||
zilliqa_nested_quorum_certificates_params: aggregate_nested_quorum_certificates_params_acc |
||||
} |
||||
|
||||
aggregate_quorum_certificates -> |
||||
aggregate_quorum_certificate_params = |
||||
AggregateQuorumCertificate.to_params(aggregate_quorum_certificates) |
||||
|
||||
aggregate_nested_quorum_certificates_params = |
||||
NestedQuorumCertificates.to_params(aggregate_quorum_certificates.quorum_certificates) |
||||
|
||||
%{ |
||||
zilliqa_aggregate_quorum_certificates_params: [ |
||||
aggregate_quorum_certificate_params | aggregate_quorum_certificates_params_acc |
||||
], |
||||
zilliqa_nested_quorum_certificates_params: |
||||
aggregate_nested_quorum_certificates_params ++ aggregate_nested_quorum_certificates_params_acc |
||||
} |
||||
end |
||||
|
||||
Map.merge(quorum_certificates_map, aggregated_quorum_certificate_map) |
||||
end |
||||
end |
@ -0,0 +1,187 @@ |
||||
defmodule EthereumJSONRPC.Zilliqa.NestedQuorumCertificates do |
||||
@moduledoc """ |
||||
Represents a list of quorum certificates that were proposed by different |
||||
validators in the aggregate quorum certificate. |
||||
""" |
||||
|
||||
import EthereumJSONRPC.Zilliqa.Helper, |
||||
only: [bit_vector_to_signers: 1] |
||||
|
||||
alias EthereumJSONRPC.Zilliqa |
||||
alias EthereumJSONRPC.Zilliqa.QuorumCertificate |
||||
|
||||
defstruct [:signers, :items] |
||||
|
||||
@type elixir :: [QuorumCertificate.elixir()] |
||||
|
||||
@type t :: %__MODULE__{ |
||||
signers: [non_neg_integer()], |
||||
items: [QuorumCertificate.t()] |
||||
} |
||||
|
||||
@type params :: %{ |
||||
proposed_by_validator_index: Zilliqa.validator_index(), |
||||
block_hash: EthereumJSONRPC.hash(), |
||||
view: non_neg_integer(), |
||||
signature: EthereumJSONRPC.hash(), |
||||
signers: Zilliqa.signers() |
||||
} |
||||
|
||||
@doc """ |
||||
Decodes the JSON object returned by JSONRPC node into the `t:t/0` format. |
||||
|
||||
## Examples |
||||
|
||||
iex> aqc_json = %{ |
||||
...> "cosigned" => "[0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", |
||||
...> "quorum_certificates" => [ |
||||
...> %{ |
||||
...> "block_hash" => "0x4b8939a7fb0d7de4b288bafd4d5caa02f53abf3c1e348fca5038eebbf68248fa", |
||||
...> "cosigned" => "[1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", |
||||
...> "signature" => "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
...> "view" => "0x115cc7" |
||||
...> }, |
||||
...> %{ |
||||
...> "block_hash" => "0x4b8939a7fb0d7de4b288bafd4d5caa02f53abf3c1e348fca5038eebbf68248fa", |
||||
...> "cosigned" => "[1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", |
||||
...> "signature" => "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
...> "view" => "0x115cc7" |
||||
...> }, |
||||
...> %{ |
||||
...> "block_hash" => "0x4b8939a7fb0d7de4b288bafd4d5caa02f53abf3c1e348fca5038eebbf68248fa", |
||||
...> "cosigned" => "[1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", |
||||
...> "signature" => "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
...> "view" => "0x115cc7" |
||||
...> }, |
||||
...> %{ |
||||
...> "block_hash" => "0x4b8939a7fb0d7de4b288bafd4d5caa02f53abf3c1e348fca5038eebbf68248fa", |
||||
...> "cosigned" => "[1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", |
||||
...> "signature" => "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
...> "view" => "0x115cc7" |
||||
...> } |
||||
...> ], |
||||
...> "signature" => "0x820f591cd78b29a69ba25bc85c4327fa3b0adb61a73a4f0bd943b4ab0b97e061eae9ac032d19fbfab7efb89fac2454ab0b89fea83185c0dac749ff55b0e2c21535a2b712872491577728db868d11939461a6bfde0d94d238f46b643bbe19767e", |
||||
...> "view" => "0x115cca" |
||||
...> } |
||||
iex> quorum_certificates = aqc_json["quorum_certificates"] |
||||
iex> bit_vector = aqc_json["cosigned"] |
||||
iex> block_hash = "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d" |
||||
iex> EthereumJSONRPC.Zilliqa.NestedQuorumCertificates.new(quorum_certificates, bit_vector, block_hash) |
||||
%EthereumJSONRPC.Zilliqa.NestedQuorumCertificates{ |
||||
signers: [1, 2, 3, 8], |
||||
items: [ |
||||
%EthereumJSONRPC.Zilliqa.QuorumCertificate{ |
||||
block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
view: 1137863, |
||||
signature: "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
signers: [0, 1, 3, 8] |
||||
}, |
||||
%EthereumJSONRPC.Zilliqa.QuorumCertificate{ |
||||
block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
view: 1137863, |
||||
signature: "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
signers: [0, 1, 3, 8] |
||||
}, |
||||
%EthereumJSONRPC.Zilliqa.QuorumCertificate{ |
||||
block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
view: 1137863, |
||||
signature: "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
signers: [0, 1, 3, 8] |
||||
}, |
||||
%EthereumJSONRPC.Zilliqa.QuorumCertificate{ |
||||
block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
view: 1137863, |
||||
signature: "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
signers: [0, 1, 3, 8] |
||||
} |
||||
] |
||||
} |
||||
""" |
||||
@spec new([QuorumCertificate.elixir()], Zilliqa.bit_vector(), EthereumJSONRPC.hash()) :: t() |
||||
def new(quorum_certificates, bit_vector, block_hash) do |
||||
signers = bit_vector_to_signers(bit_vector) |
||||
items = Enum.map(quorum_certificates, &QuorumCertificate.new(&1, block_hash)) |
||||
|
||||
%__MODULE__{ |
||||
signers: signers, |
||||
items: items |
||||
} |
||||
end |
||||
|
||||
@doc """ |
||||
Converts `t:t/0` format to params used in `Explorer.Chain`. |
||||
|
||||
## Examples |
||||
|
||||
iex> nested_quorum_certificates = %EthereumJSONRPC.Zilliqa.NestedQuorumCertificates{ |
||||
...> signers: [1, 2, 3, 8], |
||||
...> items: [ |
||||
...> %EthereumJSONRPC.Zilliqa.QuorumCertificate{ |
||||
...> block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
...> view: 1137863, |
||||
...> signature: "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
...> signers: [0, 1, 3, 8] |
||||
...> }, |
||||
...> %EthereumJSONRPC.Zilliqa.QuorumCertificate{ |
||||
...> block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
...> view: 1137863, |
||||
...> signature: "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
...> signers: [0, 1, 3, 8] |
||||
...> }, |
||||
...> %EthereumJSONRPC.Zilliqa.QuorumCertificate{ |
||||
...> block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
...> view: 1137863, |
||||
...> signature: "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
...> signers: [0, 1, 3, 8] |
||||
...> }, |
||||
...> %EthereumJSONRPC.Zilliqa.QuorumCertificate{ |
||||
...> block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
...> view: 1137863, |
||||
...> signature: "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
...> signers: [0, 1, 3, 8] |
||||
...> } |
||||
...> ] |
||||
...> } |
||||
iex> EthereumJSONRPC.Zilliqa.NestedQuorumCertificates.to_params(nested_quorum_certificates) |
||||
[ |
||||
%{ |
||||
signature: "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
view: 1137863, |
||||
signers: [0, 1, 3, 8], |
||||
proposed_by_validator_index: 1 |
||||
}, |
||||
%{ |
||||
signature: "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
view: 1137863, |
||||
signers: [0, 1, 3, 8], |
||||
proposed_by_validator_index: 2 |
||||
}, |
||||
%{ |
||||
signature: "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
view: 1137863, |
||||
signers: [0, 1, 3, 8], |
||||
proposed_by_validator_index: 3 |
||||
}, |
||||
%{ |
||||
signature: "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
view: 1137863, |
||||
signers: [0, 1, 3, 8], |
||||
proposed_by_validator_index: 8 |
||||
} |
||||
] |
||||
""" |
||||
@spec to_params(t()) :: [params()] |
||||
def to_params(%__MODULE__{signers: signers, items: items}) do |
||||
signers |
||||
|> Enum.zip(items) |
||||
|> Enum.map(fn {validator_index, cert} -> |
||||
cert |
||||
|> QuorumCertificate.to_params() |
||||
|> Map.put(:proposed_by_validator_index, validator_index) |
||||
end) |
||||
end |
||||
end |
@ -0,0 +1,100 @@ |
||||
defmodule EthereumJSONRPC.Zilliqa.QuorumCertificate do |
||||
@moduledoc """ |
||||
Represents a quorum certificate associated with the block. |
||||
""" |
||||
import EthereumJSONRPC, only: [quantity_to_integer: 1] |
||||
|
||||
import EthereumJSONRPC.Zilliqa.Helper, |
||||
only: [bit_vector_to_signers: 1] |
||||
|
||||
@type elixir :: %{ |
||||
String.t() => EthereumJSONRPC.quantity() | EthereumJSONRPC.Zilliqa.bit_vector() | EthereumJSONRPC.hash() |
||||
} |
||||
|
||||
@type t :: %__MODULE__{ |
||||
block_hash: EthereumJSONRPC.hash(), |
||||
view: non_neg_integer(), |
||||
signature: EthereumJSONRPC.hash(), |
||||
signers: [non_neg_integer()] |
||||
} |
||||
|
||||
@type params :: %{ |
||||
block_hash: EthereumJSONRPC.hash(), |
||||
view: non_neg_integer(), |
||||
signature: EthereumJSONRPC.hash(), |
||||
signers: [non_neg_integer()] |
||||
} |
||||
|
||||
defstruct [:block_hash, :view, :signature, :signers] |
||||
|
||||
@doc """ |
||||
Decodes the JSON object returned by JSONRPC node into the `t:t/0` format. |
||||
|
||||
## Examples |
||||
|
||||
iex> qc_json = %{ |
||||
...> "block_hash" => "0x4b8939a7fb0d7de4b288bafd4d5caa02f53abf3c1e348fca5038eebbf68248fa", |
||||
...> "cosigned" => "[1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]", |
||||
...> "signature" => "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
...> "view" => "0x115cc7" |
||||
...> } |
||||
iex> block_hash = "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d" |
||||
iex> EthereumJSONRPC.Zilliqa.QuorumCertificate.new(qc_json, block_hash) |
||||
%EthereumJSONRPC.Zilliqa.QuorumCertificate{ |
||||
block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
view: 1137863, |
||||
signature: "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
signers: [0, 1, 3, 8] |
||||
} |
||||
""" |
||||
@spec new(elixir(), EthereumJSONRPC.hash()) :: t() |
||||
def new( |
||||
%{ |
||||
"view" => view, |
||||
"cosigned" => bit_vector, |
||||
"signature" => signature |
||||
}, |
||||
block_hash |
||||
) do |
||||
%__MODULE__{ |
||||
block_hash: block_hash, |
||||
view: quantity_to_integer(view), |
||||
signature: signature, |
||||
signers: bit_vector_to_signers(bit_vector) |
||||
} |
||||
end |
||||
|
||||
@doc """ |
||||
Converts `t:t/0` format to params used in `Explorer.Chain`. |
||||
|
||||
## Examples |
||||
|
||||
iex> qc = %EthereumJSONRPC.Zilliqa.QuorumCertificate{ |
||||
...> block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
...> view: 1137863, |
||||
...> signature: "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
...> signers: [0, 1, 3, 8] |
||||
...> } |
||||
iex> EthereumJSONRPC.Zilliqa.QuorumCertificate.to_params(qc) |
||||
%{ |
||||
block_hash: "0x9c8a047e40ea975cb14c5ccff232a2210fbf5d77b10c748b3559ada0d4adad9d", |
||||
view: 1137863, |
||||
signature: "0xa78c7f3e07e1df963ddeda17a1e5afd97c7c8a6fc8e0616249c22a2a1cc91f8eef6073cab8ba22b50cc7b38090f1ad9109473d30f24d57858d1f28c6679b3c4deeb800e5572b5e15604596594d506d3103a44d8b707da581f1a4b82310aeecb6", |
||||
signers: [0, 1, 3, 8] |
||||
} |
||||
""" |
||||
@spec to_params(t()) :: params() |
||||
def to_params(%__MODULE__{ |
||||
block_hash: block_hash, |
||||
view: view, |
||||
signature: signature, |
||||
signers: signers |
||||
}) do |
||||
%{ |
||||
block_hash: block_hash, |
||||
view: view, |
||||
signature: signature, |
||||
signers: signers |
||||
} |
||||
end |
||||
end |
@ -0,0 +1,7 @@ |
||||
defmodule EthereumJSONRPC.ZilliqaTest do |
||||
use ExUnit.Case, async: true |
||||
|
||||
doctest EthereumJSONRPC.Zilliqa.AggregateQuorumCertificate |
||||
doctest EthereumJSONRPC.Zilliqa.NestedQuorumCertificates |
||||
doctest EthereumJSONRPC.Zilliqa.QuorumCertificate |
||||
end |
@ -0,0 +1,79 @@ |
||||
defmodule Explorer.Chain.Import.Runner.Zilliqa.AggregateQuorumCertificates do |
||||
@moduledoc """ |
||||
Bulk imports `t:Explorer.Chain.Zilliqa.AggregateQuorumCertificate.t/0`. |
||||
""" |
||||
|
||||
require Ecto.Query |
||||
|
||||
alias Ecto.{Changeset, Multi, Repo} |
||||
alias Explorer.Chain.Import |
||||
alias Explorer.Chain.Zilliqa.AggregateQuorumCertificate |
||||
alias Explorer.Prometheus.Instrumenter |
||||
|
||||
@behaviour Import.Runner |
||||
|
||||
# milliseconds |
||||
@timeout 60_000 |
||||
|
||||
@type imported :: [AggregateQuorumCertificate.t()] |
||||
|
||||
@impl Import.Runner |
||||
def ecto_schema_module, do: AggregateQuorumCertificate |
||||
|
||||
@impl Import.Runner |
||||
def option_key, do: :zilliqa_aggregate_quorum_certificates |
||||
|
||||
@impl Import.Runner |
||||
@spec imported_table_row() :: %{:value_description => binary(), :value_type => binary()} |
||||
def imported_table_row do |
||||
%{ |
||||
value_type: "[#{ecto_schema_module()}.t()]", |
||||
value_description: "List of `t:#{ecto_schema_module()}.t/0`s" |
||||
} |
||||
end |
||||
|
||||
@impl Import.Runner |
||||
@spec run(Multi.t(), list(), map()) :: Multi.t() |
||||
def run(multi, changes_list, %{timestamps: timestamps} = options) do |
||||
insert_options = |
||||
options |
||||
|> Map.get(option_key(), %{}) |
||||
|> Map.take(~w(on_conflict timeout)a) |
||||
|> Map.put_new(:timeout, @timeout) |
||||
|> Map.put(:timestamps, timestamps) |
||||
|
||||
Multi.run(multi, :insert_zilliqa_aggregate_quorum_certificates, fn repo, _ -> |
||||
Instrumenter.block_import_stage_runner( |
||||
fn -> insert(repo, changes_list, insert_options) end, |
||||
:block_referencing, |
||||
:zilliqa_aggregate_quorum_certificates, |
||||
:zilliqa_aggregate_quorum_certificates |
||||
) |
||||
end) |
||||
end |
||||
|
||||
@impl Import.Runner |
||||
def timeout, do: @timeout |
||||
|
||||
@spec insert(Repo.t(), [map()], %{required(:timeout) => timeout(), required(:timestamps) => Import.timestamps()}) :: |
||||
{:ok, [AggregateQuorumCertificate.t()]} |
||||
| {:error, [Changeset.t()]} |
||||
def insert(repo, changes_list, %{timeout: timeout, timestamps: timestamps} = _options) when is_list(changes_list) do |
||||
# Enforce Zilliqa.AggregateQuorumCertificate ShareLocks order (see docs: sharelock.md) |
||||
ordered_changes_list = Enum.sort_by(changes_list, & &1.block_hash) |
||||
|
||||
{:ok, inserted} = |
||||
Import.insert_changes_list( |
||||
repo, |
||||
ordered_changes_list, |
||||
for: AggregateQuorumCertificate, |
||||
returning: true, |
||||
timeout: timeout, |
||||
timestamps: timestamps, |
||||
conflict_target: :block_hash, |
||||
on_conflict: :nothing |
||||
) |
||||
|
||||
{:ok, inserted} |
||||
end |
||||
end |
@ -0,0 +1,86 @@ |
||||
defmodule Explorer.Chain.Import.Runner.Zilliqa.NestedQuorumCertificates do |
||||
@moduledoc """ |
||||
Bulk imports `t:Explorer.Chain.Zilliqa.NestedQuorumCertificate.t/0`. |
||||
""" |
||||
|
||||
require Ecto.Query |
||||
|
||||
alias Ecto.{Changeset, Multi, Repo} |
||||
alias Explorer.Chain.Import |
||||
alias Explorer.Chain.Zilliqa.NestedQuorumCertificate |
||||
alias Explorer.Prometheus.Instrumenter |
||||
|
||||
@behaviour Import.Runner |
||||
|
||||
# milliseconds |
||||
@timeout 60_000 |
||||
|
||||
@type imported :: [NestedQuorumCertificate.t()] |
||||
|
||||
@impl Import.Runner |
||||
def ecto_schema_module, do: NestedQuorumCertificate |
||||
|
||||
@impl Import.Runner |
||||
def option_key, do: :zilliqa_nested_quorum_certificates |
||||
|
||||
@impl Import.Runner |
||||
@spec imported_table_row() :: %{:value_description => binary(), :value_type => binary()} |
||||
def imported_table_row do |
||||
%{ |
||||
value_type: "[#{ecto_schema_module()}.t()]", |
||||
value_description: "List of `t:#{ecto_schema_module()}.t/0`s" |
||||
} |
||||
end |
||||
|
||||
@impl Import.Runner |
||||
@spec run(Multi.t(), list(), map()) :: Multi.t() |
||||
def run(multi, changes_list, %{timestamps: timestamps} = options) do |
||||
insert_options = |
||||
options |
||||
|> Map.get(option_key(), %{}) |
||||
|> Map.take(~w(on_conflict timeout)a) |
||||
|> Map.put_new(:timeout, @timeout) |
||||
|> Map.put(:timestamps, timestamps) |
||||
|
||||
Multi.run(multi, :insert_zilliqa_nested_quorum_certificates, fn repo, _ -> |
||||
Instrumenter.block_import_stage_runner( |
||||
fn -> insert(repo, changes_list, insert_options) end, |
||||
:block_referencing, |
||||
:zilliqa_nested_quorum_certificates, |
||||
:zilliqa_nested_quorum_certificates |
||||
) |
||||
end) |
||||
end |
||||
|
||||
@impl Import.Runner |
||||
def timeout, do: @timeout |
||||
|
||||
@spec insert(Repo.t(), [map()], %{required(:timeout) => timeout(), required(:timestamps) => Import.timestamps()}) :: |
||||
{:ok, [NestedQuorumCertificate.t()]} |
||||
| {:error, [Changeset.t()]} |
||||
def insert(repo, changes_list, %{timeout: timeout, timestamps: timestamps} = _options) when is_list(changes_list) do |
||||
# Enforce Zilliqa.NestedQuorumCertificate ShareLocks order (see docs: sharelock.md) |
||||
ordered_changes_list = |
||||
Enum.sort_by( |
||||
changes_list, |
||||
&{&1.block_hash, &1.proposed_by_validator_index} |
||||
) |
||||
|
||||
{:ok, inserted} = |
||||
Import.insert_changes_list( |
||||
repo, |
||||
ordered_changes_list, |
||||
for: NestedQuorumCertificate, |
||||
returning: true, |
||||
timeout: timeout, |
||||
timestamps: timestamps, |
||||
conflict_target: [ |
||||
:block_hash, |
||||
:proposed_by_validator_index |
||||
], |
||||
on_conflict: :nothing |
||||
) |
||||
|
||||
{:ok, inserted} |
||||
end |
||||
end |
@ -0,0 +1,79 @@ |
||||
defmodule Explorer.Chain.Import.Runner.Zilliqa.QuorumCertificates do |
||||
@moduledoc """ |
||||
Bulk imports `t:Explorer.Chain.Zilliqa.QuorumCertificate.t/0`. |
||||
""" |
||||
|
||||
require Ecto.Query |
||||
|
||||
alias Ecto.{Changeset, Multi, Repo} |
||||
alias Explorer.Chain.Import |
||||
alias Explorer.Chain.Zilliqa.QuorumCertificate |
||||
alias Explorer.Prometheus.Instrumenter |
||||
|
||||
@behaviour Import.Runner |
||||
|
||||
# milliseconds |
||||
@timeout 60_000 |
||||
|
||||
@type imported :: [QuorumCertificate.t()] |
||||
|
||||
@impl Import.Runner |
||||
def ecto_schema_module, do: QuorumCertificate |
||||
|
||||
@impl Import.Runner |
||||
def option_key, do: :zilliqa_quorum_certificates |
||||
|
||||
@impl Import.Runner |
||||
@spec imported_table_row() :: %{:value_description => binary(), :value_type => binary()} |
||||
def imported_table_row do |
||||
%{ |
||||
value_type: "[#{ecto_schema_module()}.t()]", |
||||
value_description: "List of `t:#{ecto_schema_module()}.t/0`s" |
||||
} |
||||
end |
||||
|
||||
@impl Import.Runner |
||||
@spec run(Multi.t(), list(), map()) :: Multi.t() |
||||
def run(multi, changes_list, %{timestamps: timestamps} = options) do |
||||
insert_options = |
||||
options |
||||
|> Map.get(option_key(), %{}) |
||||
|> Map.take(~w(on_conflict timeout)a) |
||||
|> Map.put_new(:timeout, @timeout) |
||||
|> Map.put(:timestamps, timestamps) |
||||
|
||||
Multi.run(multi, :insert_zilliqa_quorum_certificates, fn repo, _ -> |
||||
Instrumenter.block_import_stage_runner( |
||||
fn -> insert(repo, changes_list, insert_options) end, |
||||
:block_referencing, |
||||
:zilliqa_quorum_certificates, |
||||
:zilliqa_quorum_certificates |
||||
) |
||||
end) |
||||
end |
||||
|
||||
@impl Import.Runner |
||||
def timeout, do: @timeout |
||||
|
||||
@spec insert(Repo.t(), [map()], %{required(:timeout) => timeout(), required(:timestamps) => Import.timestamps()}) :: |
||||
{:ok, [QuorumCertificate.t()]} |
||||
| {:error, [Changeset.t()]} |
||||
def insert(repo, changes_list, %{timeout: timeout, timestamps: timestamps} = _options) when is_list(changes_list) do |
||||
# Enforce Zilliqa.QuorumCertificate ShareLocks order (see docs: sharelock.md) |
||||
ordered_changes_list = Enum.sort_by(changes_list, & &1.block_hash) |
||||
|
||||
{:ok, inserted} = |
||||
Import.insert_changes_list( |
||||
repo, |
||||
ordered_changes_list, |
||||
for: QuorumCertificate, |
||||
returning: true, |
||||
timeout: timeout, |
||||
timestamps: timestamps, |
||||
conflict_target: :block_hash, |
||||
on_conflict: :nothing |
||||
) |
||||
|
||||
{:ok, inserted} |
||||
end |
||||
end |
@ -0,0 +1,64 @@ |
||||
defmodule Explorer.Chain.Zilliqa.AggregateQuorumCertificate do |
||||
@moduledoc """ |
||||
A stored representation of a Zilliqa aggregate quorum certificate in the |
||||
context of PBFT consensus. |
||||
|
||||
In PBFT (Practical Byzantine Fault Tolerance) consensus, an aggregate quorum |
||||
certificate combines multiple quorum certificates into one, providing proof |
||||
that a block has been approved across multiple consensus rounds or by multiple |
||||
subsets of validators. It includes aggregated signatures and references to |
||||
nested quorum certificates. |
||||
|
||||
Changes in the schema should be reflected in the bulk import module: |
||||
- `Explorer.Chain.Import.Runner.Zilliqa.AggregateQuorumCertificate` |
||||
""" |
||||
use Explorer.Schema |
||||
|
||||
alias Explorer.Chain.{Block, Hash} |
||||
alias Explorer.Chain.Zilliqa.Hash.Signature, as: SignatureHash |
||||
alias Explorer.Chain.Zilliqa.NestedQuorumCertificate |
||||
|
||||
@required_attrs ~w(block_hash view signature)a |
||||
|
||||
@typedoc """ |
||||
* `view` - the view number associated with the quorum certificate, indicating |
||||
the consensus round. |
||||
* `signature` - the aggregated BLS (Boneh–Lynn–Shacham) signature representing |
||||
the validators' agreement. |
||||
* `block_hash` - the hash of the block associated with this aggregate quorum |
||||
certificate. |
||||
* `nested_quorum_certificates` - the list of nested quorum certificates that |
||||
are part of this aggregate. |
||||
""" |
||||
@primary_key false |
||||
typed_schema "zilliqa_aggregate_quorum_certificates" do |
||||
field(:view, :integer) |
||||
field(:signature, SignatureHash) |
||||
|
||||
belongs_to(:block, Block, |
||||
foreign_key: :block_hash, |
||||
primary_key: true, |
||||
references: :hash, |
||||
type: Hash.Full, |
||||
null: false |
||||
) |
||||
|
||||
has_many( |
||||
:nested_quorum_certificates, |
||||
NestedQuorumCertificate, |
||||
foreign_key: :block_hash, |
||||
references: :block_hash |
||||
) |
||||
|
||||
timestamps() |
||||
end |
||||
|
||||
@spec changeset(Ecto.Schema.t(), map()) :: Ecto.Changeset.t() |
||||
def changeset(%__MODULE__{} = cert, attrs) do |
||||
cert |
||||
|> cast(attrs, @required_attrs) |
||||
|> validate_required(@required_attrs) |
||||
|> foreign_key_constraint(:block_hash) |
||||
|> unique_constraint(:block_hash, name: :aggregate_quorum_certificates_pkey) |
||||
end |
||||
end |
@ -0,0 +1,60 @@ |
||||
defmodule Explorer.Chain.Zilliqa.Hash.Signature do |
||||
@moduledoc """ |
||||
A 96-byte BLS signature of the supermajority of the validators. |
||||
""" |
||||
|
||||
alias Explorer.Chain.Hash |
||||
|
||||
use Ecto.Type |
||||
@behaviour Hash |
||||
|
||||
@byte_count 96 |
||||
|
||||
@typedoc """ |
||||
A #{@byte_count}-byte BLS signature hash of the |
||||
`t:Explorer.Chain.Zilliqa.QuorumCertificate.t/0` or |
||||
`t:Explorer.Chain.Zilliqa.AggregateQuorumCertificate.t/0` or |
||||
`t:Explorer.Chain.Zilliqa.NestedQuorumCertificate.t/0`. |
||||
""" |
||||
@type t :: %Hash{byte_count: unquote(@byte_count), bytes: <<_::unquote(@byte_count * Hash.bits_per_byte())>>} |
||||
|
||||
@doc """ |
||||
Casts a term to a `t`. |
||||
""" |
||||
@impl Ecto.Type |
||||
@spec cast(term()) :: {:ok, t()} | :error |
||||
def cast(term) do |
||||
Hash.cast(__MODULE__, term) |
||||
end |
||||
|
||||
@doc """ |
||||
Dumps a `t` to a binary. |
||||
""" |
||||
@impl Ecto.Type |
||||
@spec dump(term()) :: {:ok, binary} | :error |
||||
def dump(term) do |
||||
Hash.dump(__MODULE__, term) |
||||
end |
||||
|
||||
@doc """ |
||||
Loads a binary to a `t`. |
||||
""" |
||||
@impl Ecto.Type |
||||
@spec load(term()) :: {:ok, t()} | :error |
||||
def load(term) do |
||||
Hash.load(__MODULE__, term) |
||||
end |
||||
|
||||
@doc """ |
||||
Returns the type of the `t`. |
||||
""" |
||||
@impl Ecto.Type |
||||
@spec type() :: :binary |
||||
def type, do: :binary |
||||
|
||||
@doc """ |
||||
Returns the byte count of the `t`. |
||||
""" |
||||
@impl Hash |
||||
def byte_count, do: @byte_count |
||||
end |
@ -0,0 +1,64 @@ |
||||
defmodule Explorer.Chain.Zilliqa.NestedQuorumCertificate do |
||||
@moduledoc """ |
||||
A stored representation of a nested quorum certificate in Zilliqa's PBFT |
||||
consensus. |
||||
|
||||
In Zilliqa's PBFT (Practical Byzantine Fault Tolerance) consensus, an |
||||
aggregate quorum certificate may include multiple nested quorum certificates. |
||||
Each nested quorum certificate represents a quorum certificate proposed by a |
||||
specific validator and contains its own aggregated signatures and participant |
||||
information. |
||||
|
||||
Changes in the schema should be reflected in the bulk import module: |
||||
- `Explorer.Chain.Import.Runner.Zilliqa.AggregateQuorumCertificate` |
||||
""" |
||||
use Explorer.Schema |
||||
|
||||
alias Explorer.Chain.Hash |
||||
alias Explorer.Chain.Zilliqa.AggregateQuorumCertificate |
||||
alias Explorer.Chain.Zilliqa.Hash.Signature, as: SignatureHash |
||||
|
||||
@required_attrs ~w(block_hash proposed_by_validator_index view signature signers)a |
||||
|
||||
@typedoc """ |
||||
* `proposed_by_validator_index` - the index of the validator who proposed this |
||||
nested quorum certificate. |
||||
* `view` - the view number associated with the quorum certificate, indicating |
||||
the consensus round. |
||||
* `signature` - the aggregated BLS (Boneh–Lynn–Shacham) signature representing |
||||
the validators' agreement. |
||||
* `signers` - the array of integers representing the indices of validators who |
||||
participated in the quorum (as indicated by the `cosigned` bit vector). |
||||
* `block_hash` - the hash of the block associated with the aggregate quorum |
||||
certificate to which this nested quorum certificate belongs. |
||||
""" |
||||
@primary_key false |
||||
typed_schema "zilliqa_nested_quorum_certificates" do |
||||
field(:proposed_by_validator_index, :integer, primary_key: true) |
||||
field(:view, :integer) |
||||
field(:signature, SignatureHash) |
||||
field(:signers, {:array, :integer}) |
||||
|
||||
belongs_to(:aggregate_quorum_certificate, AggregateQuorumCertificate, |
||||
foreign_key: :block_hash, |
||||
references: :block_hash, |
||||
primary_key: true, |
||||
type: Hash.Full, |
||||
null: false |
||||
) |
||||
|
||||
timestamps() |
||||
end |
||||
|
||||
@spec changeset(Ecto.Schema.t(), map()) :: Ecto.Changeset.t() |
||||
def changeset(%__MODULE__{} = cert, attrs) do |
||||
cert |
||||
|> cast(attrs, @required_attrs) |
||||
|> validate_required(@required_attrs) |
||||
|> foreign_key_constraint(:block_hash) |
||||
|> unique_constraint( |
||||
[:proposed_by_validator_index, :block_hash], |
||||
name: :nested_quorum_certificates_pkey |
||||
) |
||||
end |
||||
end |
@ -0,0 +1,56 @@ |
||||
defmodule Explorer.Chain.Zilliqa.QuorumCertificate do |
||||
@moduledoc """ |
||||
A stored representation of a Zilliqa quorum certificate in the context of PBFT |
||||
consensus. |
||||
|
||||
In PBFT (Practical Byzantine Fault Tolerance) consensus, a quorum certificate |
||||
is a data structure that serves as proof that a block has been approved by a |
||||
supermajority of validators. It includes aggregated signatures and a bitmap |
||||
indicating which validators participated in the consensus. |
||||
|
||||
Changes in the schema should be reflected in the bulk import module: |
||||
- `Explorer.Chain.Import.Runner.Zilliqa.AggregateQuorumCertificate` |
||||
""" |
||||
use Explorer.Schema |
||||
|
||||
alias Explorer.Chain.{Block, Hash} |
||||
alias Explorer.Chain.Zilliqa.Hash.Signature, as: SignatureHash |
||||
|
||||
@required_attrs ~w(block_hash view signature signers)a |
||||
|
||||
@typedoc """ |
||||
* `view` - the view number associated with the quorum certificate, indicating |
||||
the consensus round. |
||||
* `signature` - the aggregated BLS (Boneh–Lynn–Shacham) signature representing |
||||
the validators' agreement. |
||||
* `signers` - the array of integers representing the indices of validators who |
||||
participated in the quorum (as indicated by the `cosigned` bit vector). |
||||
* `block_hash` - the hash of the block associated with this quorum |
||||
certificate. |
||||
""" |
||||
@primary_key false |
||||
typed_schema "zilliqa_quorum_certificates" do |
||||
field(:view, :integer) |
||||
field(:signature, SignatureHash) |
||||
field(:signers, {:array, :integer}) |
||||
|
||||
belongs_to(:block, Block, |
||||
foreign_key: :block_hash, |
||||
primary_key: true, |
||||
references: :hash, |
||||
type: Hash.Full, |
||||
null: false |
||||
) |
||||
|
||||
timestamps() |
||||
end |
||||
|
||||
@spec changeset(Ecto.Schema.t(), map()) :: Ecto.Schema.t() |
||||
def changeset(%__MODULE__{} = cert, attrs) do |
||||
cert |
||||
|> cast(attrs, @required_attrs) |
||||
|> validate_required(@required_attrs) |
||||
|> foreign_key_constraint(:block_hash) |
||||
|> unique_constraint(:block_hash, name: :quorum_certificates_pkey) |
||||
end |
||||
end |
@ -0,0 +1,20 @@ |
||||
defmodule Explorer.Repo.Zilliqa.Migrations.CreateQuorumCertificate do |
||||
use Ecto.Migration |
||||
|
||||
def change do |
||||
create table(:zilliqa_quorum_certificates, primary_key: false) do |
||||
add( |
||||
:block_hash, |
||||
references(:blocks, column: :hash, type: :bytea, on_delete: :delete_all), |
||||
null: false, |
||||
primary_key: true |
||||
) |
||||
|
||||
add(:view, :integer, null: false) |
||||
add(:signature, :binary, null: false) |
||||
add(:signers, {:array, :smallint}, null: false) |
||||
|
||||
timestamps() |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,19 @@ |
||||
defmodule Explorer.Repo.Zilliqa.Migrations.CreateAggregateQuorumCertificate do |
||||
use Ecto.Migration |
||||
|
||||
def change do |
||||
create table(:zilliqa_aggregate_quorum_certificates, primary_key: false) do |
||||
add( |
||||
:block_hash, |
||||
references(:blocks, column: :hash, type: :bytea, on_delete: :delete_all), |
||||
null: false, |
||||
primary_key: true |
||||
) |
||||
|
||||
add(:view, :integer, null: false) |
||||
add(:signature, :binary, null: false) |
||||
|
||||
timestamps() |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,21 @@ |
||||
defmodule Explorer.Repo.Zilliqa.Migrations.CreateNestedQuorumCertificate do |
||||
use Ecto.Migration |
||||
|
||||
def change do |
||||
create table(:zilliqa_nested_quorum_certificates, primary_key: false) do |
||||
add( |
||||
:block_hash, |
||||
references(:blocks, column: :hash, type: :bytea, on_delete: :delete_all), |
||||
null: false, |
||||
primary_key: true |
||||
) |
||||
|
||||
add(:proposed_by_validator_index, :smallint, primary_key: true) |
||||
add(:view, :integer, null: false) |
||||
add(:signature, :binary, null: false) |
||||
add(:signers, {:array, :smallint}, null: false) |
||||
|
||||
timestamps() |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,9 @@ |
||||
defmodule Explorer.Repo.Zilliqa.Migrations.AddViewToBlock do |
||||
use Ecto.Migration |
||||
|
||||
def change do |
||||
alter table(:blocks) do |
||||
add(:zilliqa_view, :integer) |
||||
end |
||||
end |
||||
end |
Loading…
Reference in new issue