diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml
new file mode 100644
index 0000000000..6387af06aa
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug-report.yml
@@ -0,0 +1,62 @@
+name: ๐ Bug
+description: File a bug/issue
+title: "bug: "
+labels: [bug]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ _The more information you share, the faster we can help you._
+ Prior to opening the issue, please make sure that you:
+ - Use English (EN/US) to communicate.
+ - Search the [open issues](https://github.com/hyperledger/firefly/issues) to avoid duplicating the issue.
+
+ - type: textarea
+ id: problem
+ attributes:
+ label: What happened?
+ description: |
+ Please provide as much info as possible. Not doing so may result in your bug not being addressed in a timely manner.
+ If this matter is security related, please disclose it privately via security@lfdecentralizedtrust.org
+ validations:
+ required: true
+
+ - type: textarea
+ id: expected
+ attributes:
+ label: What did you expect to happen?
+ validations:
+ required: true
+
+ - type: textarea
+ id: repro
+ attributes:
+ label: How can we reproduce it (as minimally and precisely as possible)?
+ validations:
+ required: true
+
+ - type: textarea
+ id: additional
+ attributes:
+ label: Anything else we need to know?
+
+ - type: textarea
+ id: osVersion
+ attributes:
+ label: OS version
+ value: |
+
+
+ ```console
+ # On Linux:
+ $ cat /etc/os-release
+ # paste output here
+ $ uname -a
+ # paste output here
+
+ # On Windows:
+ C:\> wmic os get Caption, Version, BuildNumber, OSArchitecture
+ # paste output here
+ ```
+
+
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000000..51cdb2da77
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,5 @@
+blank_issues_enabled: false
+contact_links:
+ - name: Support Request
+ url: https://discord.gg/hyperledger
+ about: Support request or question relating to Hyperledger Firefly
diff --git a/.github/ISSUE_TEMPLATE/enhancement.yml b/.github/ISSUE_TEMPLATE/enhancement.yml
new file mode 100644
index 0000000000..7ba36d42b2
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/enhancement.yml
@@ -0,0 +1,27 @@
+name: Enhancement Tracking Issue
+description: Provide supporting details for an enhancement
+labels: [enhancement]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ _The more information you share, the faster we can help you._
+ Prior to opening the issue, please make sure that you:
+ - Use English (EN/US) to communicate.
+ - Search the [open issues](https://github.com/hyperledger/firefly/issues) to avoid duplicating the issue.
+
+ - type: textarea
+ id: enhancement
+ attributes:
+ label: What would you like to be added?
+ description: |
+ A clear and concise description of what you want to happen.
+ validations:
+ required: true
+
+ - type: textarea
+ id: rationale
+ attributes:
+ label: Why is this needed?
+ validations:
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/improve_docs.yml b/.github/ISSUE_TEMPLATE/improve_docs.yml
new file mode 100644
index 0000000000..13220bcdc2
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/improve_docs.yml
@@ -0,0 +1,31 @@
+name: "Documentation Issue"
+description: Issues related to documentation.
+title: "docs: "
+labels: [documentation]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ _The more information you share, the faster we can help you._
+ Prior to opening the issue, please make sure that you:
+ - Use English (EN/US) to communicate.
+ - Search the [open issues](https://github.com/hyperledger/firefly/issues) to avoid duplicating the issue.
+
+ - type: textarea
+ id: current-state
+ attributes:
+ label: Current State
+ description: Describe the current state of the documentation.
+ placeholder: |
+ The documentation for the API in this page (url) is missing ...
+ validations:
+ required: true
+ - type: textarea
+ id: desired-state
+ attributes:
+ label: Desired State
+ description: Describe the desired state the documentation should be in.
+ placeholder: |
+ Add here ...
+ validations:
+ required: true
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000000..7cd0724717
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,45 @@
+
+
+## Proposed changes
+
+Please include a summary of the changes here and why we need those changes. And also let us know which issue is fixed.
+
+Fixes #
+
+
+
+## Types of changes
+
+
+
+
+
+- [ ] Bug fix
+- [ ] New feature added
+- [ ] Documentation Update
+
+
+
+## Please make sure to follow these points
+
+
+
+
+
+- [ ] I have read the contributing guidelines.
+- [ ] I have performed a self-review of my own code or work.
+- [ ] I have commented my code, particularly in hard-to-understand areas.
+- [ ] My changes generates no new warnings.
+- [ ] I have added tests that prove my fix is effective or that my feature works.
+- [ ] My changes have sufficient code coverage (unit, integration, e2e tests).
+
+
+
+## Screenshots (If Applicable)
+
+
+
+
+## Other Information
+
+Any message for the reviewer or kick off the discussion by explaining why you considered this particular solution, any alternatives etc.
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
new file mode 100644
index 0000000000..9ce1cb3bc2
--- /dev/null
+++ b/.github/workflows/codeql.yml
@@ -0,0 +1,40 @@
+name: "CodeQL"
+
+on:
+ pull_request:
+ branches:
+ - main
+ push:
+ branches:
+ - main
+ workflow_dispatch:
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+permissions:
+ contents: read
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-latest
+ permissions:
+ security-events: write
+ strategy:
+ fail-fast: false
+ matrix:
+ language:
+ - go
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v3
+ with:
+ languages: ${{ matrix.language }}
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@v3
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v3
diff --git a/.github/workflows/docker_main.yml b/.github/workflows/docker_main.yml
index 94eadaf729..30d2c10ad1 100644
--- a/.github/workflows/docker_main.yml
+++ b/.github/workflows/docker_main.yml
@@ -8,11 +8,13 @@ on:
- '.github/**' # exclude .github directory
- '**.md' # exclude all markdown files
+permissions:
+ contents: read
+
jobs:
docker:
runs-on: ubuntu-latest
permissions:
- contents: read
packages: write
steps:
- uses: actions/checkout@v3
diff --git a/.github/workflows/docker_release.yml b/.github/workflows/docker_release.yml
index 11a5c311a0..9fdabe043f 100644
--- a/.github/workflows/docker_release.yml
+++ b/.github/workflows/docker_release.yml
@@ -4,12 +4,14 @@ on:
release:
types: [released, prereleased]
+permissions:
+ contents: read
+
jobs:
docker:
runs-on: ubuntu-latest
permissions:
- contents: read
packages: write
steps:
- uses: actions/checkout@v4
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 7922048bcd..331fe22890 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -7,6 +7,10 @@ on:
pull_request:
release:
types: [released]
+
+permissions:
+ contents: read
+
jobs:
build:
runs-on: ubuntu-latest
@@ -26,7 +30,7 @@ jobs:
- name: Get the latest tag
run: |
git fetch --tags
- latest_tag=$(git tag -l | sort -V | tail -n 1)
+ latest_tag=$(git tag -l | sort -V | grep -v "rc" | tail -n 1)
echo "latest tag: $latest_tag"
echo "LATEST_TAG=$latest_tag" >> $GITHUB_ENV
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 74d832b7b3..fe7fc78a79 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -2,7 +2,7 @@ name: Go
on:
push:
- branches: [main]
+ branches: [main]
paths:
- '**' # include all files
- '!.github/**' # exclude .github directory
@@ -18,6 +18,9 @@ on:
workflow_dispatch:
+permissions:
+ contents: read
+
jobs:
build:
env:
@@ -60,7 +63,7 @@ jobs:
run: docker save --output firefly.tar.gz hyperledger/firefly
- name: Upload Docker image
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: firefly-docker
path: firefly.tar.gz
@@ -146,7 +149,7 @@ jobs:
go-version: 1.22
- name: Download Docker image
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
with:
name: firefly-docker
@@ -165,7 +168,7 @@ jobs:
run: ./test/e2e/run.sh
- name: Archive container logs
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
if: always()
with:
name: container-logs-${{ matrix.test-suite }}-${{ matrix.blockchain-provider }}-${{ matrix.blockchain-connector }}-${{ matrix.database-type }}-${{ matrix.token-provider }}
diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml
index 91da3d7f16..256b3bc77b 100644
--- a/.github/workflows/integration.yml
+++ b/.github/workflows/integration.yml
@@ -7,6 +7,9 @@ on:
- cron: "0 0 * * *"
workflow_dispatch:
+permissions:
+ contents: read
+
jobs:
e2e-test:
runs-on: firefly-ubuntu-latest
@@ -75,7 +78,7 @@ jobs:
run: ./test/e2e/run.sh
- name: Archive container logs
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
if: always()
with:
name: container-logs-${{ matrix.test-suite }}-${{ matrix.blockchain-node }}-${{ matrix.database-type }}
@@ -111,7 +114,7 @@ jobs:
run: ./test/e2e/run.sh
- name: Archive container logs
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
if: always()
with:
name: container-logs-TestEthereumV1MigrationE2ESuite-geth-postgres
diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml
new file mode 100644
index 0000000000..d8649cc3f7
--- /dev/null
+++ b/.github/workflows/scorecard.yml
@@ -0,0 +1,73 @@
+# This workflow uses actions that are not certified by GitHub. They are provided
+# by a third-party and are governed by separate terms of service, privacy
+# policy, and support documentation.
+
+name: Scorecard supply-chain security
+on:
+ # For Branch-Protection check. Only the default branch is supported. See
+ # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
+ branch_protection_rule:
+ # To guarantee Maintained check is occasionally updated. See
+ # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
+ schedule:
+ - cron: '24 7 * * 4'
+ push:
+ branches: [ "main" ]
+
+# Declare default permissions as read only.
+permissions: read-all
+
+jobs:
+ analysis:
+ name: Scorecard analysis
+ runs-on: ubuntu-latest
+ permissions:
+ # Needed to upload the results to code-scanning dashboard.
+ security-events: write
+ # Needed to publish results and get a badge (see publish_results below).
+ id-token: write
+ # Uncomment the permissions below if installing in a private repository.
+ # contents: read
+ # actions: read
+
+ steps:
+ - name: "Checkout code"
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ with:
+ persist-credentials: false
+
+ - name: "Run analysis"
+ uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
+ with:
+ results_file: results.sarif
+ results_format: sarif
+ # (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
+ # - you want to enable the Branch-Protection check on a *public* repository, or
+ # - you are installing Scorecard on a *private* repository
+ # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action?tab=readme-ov-file#authentication-with-fine-grained-pat-optional.
+ repo_token: ${{ secrets.SCORECARD_TOKEN }}
+
+ # Public repositories:
+ # - Publish results to OpenSSF REST API for easy access by consumers
+ # - Allows the repository to include the Scorecard badge.
+ # - See https://github.com/ossf/scorecard-action#publishing-results.
+ # For private repositories:
+ # - `publish_results` will always be set to `false`, regardless
+ # of the value entered here.
+ publish_results: true
+
+ # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
+ # format to the repository Actions tab.
+ - name: "Upload artifact"
+ uses: actions/upload-artifact@v4
+ with:
+ name: SARIF file
+ path: results.sarif
+ retention-days: 5
+
+ # Upload the results to GitHub's code scanning dashboard (optional).
+ # Commenting out will disable upload of results to your repo's Code Scanning dashboard
+ - name: "Upload to code-scanning"
+ uses: github/codeql-action/upload-sarif@v3
+ with:
+ sarif_file: results.sarif
diff --git a/.github/workflows/solidity.yml b/.github/workflows/solidity.yml
index 47ebecd615..bd69f84ec2 100644
--- a/.github/workflows/solidity.yml
+++ b/.github/workflows/solidity.yml
@@ -4,6 +4,10 @@ on:
pull_request:
branches: [main]
+permissions:
+ contents: read
+ packages: read
+
jobs:
solidity-test:
runs-on: ubuntu-latest
diff --git a/.gitignore b/.gitignore
index f716852eb8..0d73ffa57f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,5 +12,6 @@ __debug*
!deploy/charts/firefly
containerlogs
.vscode/*.log
-.idea
-doc-site/site
\ No newline at end of file
+.idea/
+doc-site/site
+*.iml
diff --git a/.golangci.yml b/.golangci.yml
index e5221806bc..87bbf218a7 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -21,6 +21,7 @@ linters-settings:
values:
regexp:
COMPANY: .*
+ YEAR: '\d\d\d\d(-\d\d\d\d)?'
template: |-
Copyright ยฉ {{ YEAR }} {{ COMPANY }}
diff --git a/Dockerfile b/Dockerfile
index c5632b71b8..a781407d2d 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
# ARG Definitions
-# Consider adding default values for the ARGs based on this warning:
+# Consider adding default values for the ARGs based on this warning:
# https://github.com/hyperledger/firefly/actions/runs/10795366695/job/29941873807#step:4:171
ARG FIREFLY_BUILDER_TAG
ARG FABRIC_BUILDER_TAG
@@ -15,16 +15,16 @@ FROM $FIREFLY_BUILDER_TAG AS firefly-builder
ARG BUILD_VERSION
ARG GIT_REF
RUN apk add make=4.4.1-r2 \
- gcc=13.2.1_git20231014-r0 \
- build-base=0.5-r3 \
- curl=8.9.1-r1 \
- git=2.43.5-r0
+ gcc=13.2.1_git20231014-r0 \
+ build-base=0.5-r3 \
+ curl=8.12.1-r0 \
+ git=2.43.6-r0
WORKDIR /firefly
RUN chgrp -R 0 /firefly \
- && chmod -R g+rwX /firefly \
- && mkdir /.cache \
- && chgrp -R 0 /.cache \
- && chmod -R g+rwX /.cache
+ && chmod -R g+rwX /firefly \
+ && mkdir /.cache \
+ && chgrp -R 0 /.cache \
+ && chmod -R g+rwX /.cache
USER 1001
ADD --chown=1001:0 go.mod go.sum ./
RUN go mod download
@@ -35,10 +35,10 @@ RUN make build
FROM --platform=$FABRIC_BUILDER_PLATFORM $FABRIC_BUILDER_TAG AS fabric-builder
WORKDIR /firefly/smart_contracts/fabric/firefly-go
RUN chgrp -R 0 /firefly \
- && chmod -R g+rwX /firefly \
- && mkdir /.cache \
- && chgrp -R 0 /.cache \
- && chmod -R g+rwX /.cache
+ && chmod -R g+rwX /firefly \
+ && mkdir /.cache \
+ && chgrp -R 0 /.cache \
+ && chmod -R g+rwX /.cache
USER 1001
ADD --chown=1001:0 smart_contracts/fabric/firefly-go .
RUN GO111MODULE=on go mod vendor
@@ -55,45 +55,45 @@ RUN chgrp -R 0 /firefly && chmod -R g+rwX /firefly
ADD --chown=1001:0 smart_contracts/ethereum/solidity_firefly/ .
USER 1001
RUN mkdir -p build/contracts \
- && cd contracts \
- && solc --combined-json abi,bin,devdoc -o ../build/contracts Firefly.sol \
- && cd ../build/contracts \
- && mv combined.json Firefly.json
+ && cd contracts \
+ && solc --combined-json abi,bin,devdoc -o ../build/contracts Firefly.sol \
+ && cd ../build/contracts \
+ && mv combined.json Firefly.json
# SBOM
FROM alpine:3.19 AS sbom
WORKDIR /
ADD . /SBOM
-RUN apk add --no-cache curl
+RUN apk add --no-cache curl
RUN curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin v0.48.3
RUN trivy fs --format spdx-json --output /sbom.spdx.json /SBOM
-RUN trivy sbom /sbom.spdx.json --severity UNKNOWN,HIGH,CRITICAL --exit-code 1
+RUN trivy sbom /sbom.spdx.json --severity UNKNOWN,HIGH,CRITICAL --db-repository public.ecr.aws/aquasecurity/trivy-db --exit-code 1
# Final executable build
FROM $BASE_TAG
ARG UI_TAG
ARG UI_RELEASE
RUN apk add --update --no-cache \
- sqlite=3.44.2-r0 \
- postgresql16-client=16.4-r0 \
- curl=8.9.1-r1 \
- jq=1.7.1-r0
+ sqlite=3.44.2-r0 \
+ postgresql16-client=16.8-r0 \
+ curl=8.12.1-r0 \
+ jq=1.7.1-r0
WORKDIR /firefly
RUN chgrp -R 0 /firefly \
- && chmod -R g+rwX /firefly \
- && mkdir /etc/firefly \
- && chgrp -R 0 /etc/firefly \
- && chmod -R g+rwX /etc/firefly
+ && chmod -R g+rwX /firefly \
+ && mkdir /etc/firefly \
+ && chgrp -R 0 /etc/firefly \
+ && chmod -R g+rwX /etc/firefly
RUN curl -sL "https://github.com/golang-migrate/migrate/releases/download/$(curl -sL https://api.github.com/repos/golang-migrate/migrate/releases/latest | jq -r '.name')/migrate.linux-amd64.tar.gz" | tar xz \
- && chmod +x ./migrate \
- && mv ./migrate /usr/bin/migrate
+ && chmod +x ./migrate \
+ && mv ./migrate /usr/bin/migrate
COPY --from=firefly-builder --chown=1001:0 /firefly/firefly ./firefly
COPY --from=firefly-builder --chown=1001:0 /firefly/db ./db
COPY --from=solidity-builder --chown=1001:0 /firefly/solidity_firefly/build/contracts ./contracts
COPY --from=fabric-builder --chown=1001:0 /firefly/smart_contracts/fabric/firefly-go/firefly_fabric.tar.gz ./contracts/firefly_fabric.tar.gz
ENV UI_RELEASE=https://github.com/hyperledger/firefly-ui/releases/download/$UI_TAG/$UI_RELEASE.tgz
RUN mkdir /firefly/frontend \
- && curl -sLo - $UI_RELEASE | tar -C /firefly/frontend -zxvf -
+ && curl -sLo - $UI_RELEASE | tar -C /firefly/frontend -zxvf -
COPY --from=sbom /sbom.spdx.json /sbom.spdx.json
RUN ln -s /firefly/firefly /usr/bin/firefly
USER 1001
diff --git a/Makefile b/Makefile
index bcd40335eb..d77d30cb73 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ GOGC=30
all: build test go-mod-tidy
test: deps lint
- $(VGO) test ./internal/... ./pkg/... ./cmd/... ./doc-site ./ffconfig/... -cover -coverprofile=coverage.txt -covermode=atomic -timeout=30s ${TEST_ARGS}
+ $(VGO) test ./internal/... ./pkg/... ./cmd/... ./doc-site ./ffconfig/... -cover -coverprofile=coverage.txt -covermode=atomic -timeout=45s ${TEST_ARGS}
coverage.html:
$(VGO) tool cover -html=coverage.txt
coverage: test coverage.html
diff --git a/README.md b/README.md
index 6123bdcd69..2b58d5a697 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,7 @@
[](https://hyperledger.github.io/firefly//)

[](https://www.bestpractices.dev/projects/7826)
+[](https://scorecard.dev/viewer/?uri=github.com/hyperledger/firefly)

@@ -12,6 +13,8 @@ Hyperledger FireFly is the first open source Supernode: a complete stack for ent
The FireFly API for digital assets, data flows, and blockchain transactions makes it radically faster to build production-ready apps on popular chains and protocols.
+[ENGLISH](./README.md) | [็ฎไฝไธญๆ](./README_zh_CN.md)
+
## Start using Hyperledger FireFly
The best place to learn about FireFly is in the [documentation](https://hyperledger.github.io/firefly).
@@ -40,7 +43,7 @@ all the plumbing for your blockchain application from scratch.
[](https://raw.githubusercontent.com/kaleido-io/firefly/main/doc-site/docs/images/firefly_architecture_overview.jpg)
-## Start contributing to Hyperledger FireFy
+## Start contributing to Hyperledger FireFly
There are lots of places you can contribute, regardless of whether your skills are front-end, backend-end, or full-stack.
@@ -58,35 +61,35 @@ Other repositories you might be interested in containing those microservice comp
### Blockchain connectivity
-- Transaction Manager - https://github.com/hyperledger/firefly-transaction-manager
-- RLP & ABI encoding, KeystoreV3 utilities and secp256k1 signer runtime - https://github.com/hyperledger/firefly-signer
-- FFCAPI reference connector for EVM Chains - https://github.com/hyperledger/firefly-evmconnect
+- Transaction Manager -
+- RLP & ABI encoding, KeystoreV3 utilities and secp256k1 signer runtime -
+- FFCAPI reference connector for EVM Chains -
- Public EVM compatible chains: Learn more in the [documentation](https://hyperledger.github.io/firefly)
-- Permissioned Ethereum connector - https://github.com/hyperledger/firefly-ethconnect
+- Permissioned Ethereum connector -
- Private/permissioned: Hyperledger Besu / Quorum
-- Hyperledger Fabric connector - https://github.com/hyperledger/firefly-fabconnect
-- Tezos connector - https://github.com/hyperledger/firefly-tezosconnect
-- Corda connector starter: https://github.com/hyperledger/firefly-cordaconnect
+- Hyperledger Fabric connector -
+- Tezos connector -
+- Corda connector starter:
- CorDapp specific customization is required
### Token standards
-- Tokens ERC20/ERC721 - https://github.com/hyperledger/firefly-tokens-erc20-erc721
-- Tokens ERC1155 - https://github.com/hyperledger/firefly-tokens-erc1155
+- Tokens ERC20/ERC721 -
+- Tokens ERC1155 -
### Private data bus connectivity
-- HTTPS Data Exchange - https://github.com/hyperledger/firefly-dataexchange-https
+- HTTPS Data Exchange -
### Developer ecosystem
-- Command Line Interface (CLI) - https://github.com/hyperledger/firefly-cli
-- Explorer UI - https://github.com/hyperledger/firefly-ui
-- Node.js SDK - https://github.com/hyperledger/firefly-sdk-nodejs
-- Sandbox / Exerciser - https://github.com/hyperledger/firefly-sandbox
-- Samples - https://github.com/hyperledger/firefly-samples
-- FireFly Performance CLI: https://github.com/hyperledger/firefly-perf-cli
-- Helm Charts for Deploying to Kubernetes: https://github.com/hyperledger/firefly-helm-charts
+- Command Line Interface (CLI) -
+- Explorer UI -
+- Node.js SDK -
+- Sandbox / Exerciser -
+- Samples -
+- FireFly Performance CLI:
+- Helm Charts for Deploying to Kubernetes:
## FireFly Core code hierarchy
diff --git a/README_zh_CN.md b/README_zh_CN.md
new file mode 100644
index 0000000000..37d39e99a4
--- /dev/null
+++ b/README_zh_CN.md
@@ -0,0 +1,347 @@
+# Hyperledger FireFly
+
+[](https://codecov.io/gh/hyperledger/firefly)
+[](https://goreportcard.com/report/github.com/hyperledger/firefly)
+[](https://hyperledger.github.io/firefly//)
+
+[](https://www.bestpractices.dev/projects/7826)
+[](https://scorecard.dev/viewer/?uri=github.com/hyperledger/firefly)
+
+
+
+Hyperledger FireFly ๆฏ้ฆๆฌพๅผๆบ็่ถ
็บง่็น๏ผไธไธชๅฎๅ
จ็ไผไธ็บง็ๆๅปบๅๆๅฑWeb3ๅบ็จ็ๅ
จๆ ๅผ่งฃๅณๆนๆกใ
+
+FireFly ๆไพ็ๆฐๅญ่ตไบงใๆฐๆฎๆตๅๅบๅ้พไบคๆAPI๏ผไฝฟไผไธ่ฝๅคๅฟซ้ๅจๆต่ก็ๅบๅ้พๆๆฏๅๅ่ฎฎไธๆๅปบ็ไบงๅฐฑ็ปช็ๅบ็จ็จๅบใ
+
+[ENGLISH](./README.md) | [็ฎไฝไธญๆ](./README_zh_CN.md)
+
+## ๅผๅงไฝฟ็จ Hyperledger FireFly
+
+ไบ่งฃFireFly็ๆไฝณๆนๅผ่ฏทๅ็
ง[ๆๆกฃ](https://hyperledger.github.io/firefly)ใ
+
+ๆจๅฏไปฅๅจ่ฟ้ๆพๅฐๆไปฌ็[ๅ
ฅ้จๆๅ](https://hyperledger.github.io/firefly/latest/gettingstarted/),
+้่ฟ่ฏฅๆๅๅฐๅธฎๅฉๆจๅจๅ ๅ้ๅ
ๅจๆฌๅฐๆบๅจไธ่ฟ่ก่ตทๆฅไธไธชFireFly่ถ
็บง่็น็ฝ็ป็ๅผๅ็ฏๅขใ
+
+ๆจ็ๅผๅ็ฏๅขๅฐๅ
ๆฌ:
+
+FireFly CLI | FireFly Explorer UI | FireFly Sandbox |
+:----------------------------:|:-----------------------------------:|:----------------:|
+[](https://hyperledger.github.io/firefly/latest/gettingstarted/firefly_cli/#install-the-firefly-cli) | [](https://github.com/hyperledger/firefly-ui) | [](https://hyperledger.github.io/firefly/latest/gettingstarted/sandbox/#use-the-sandbox) |
+
+## ๅ ๅ
ฅ็คพๅบ
+
+- [ๅ ๅ
ฅๆไปฌ็ Discord](https://discord.gg/hyperledger)
+
+## ๆๆฏๆถๆ
+
+Hyperledger FireFly ๆฅๆๅฏๆๆ็ๅพฎๆๅกๆถๆใๆ ่ฎบๆฏๅบๅ้พๅ่ฎฎใERCไปฃๅธๆ ๅใ่ชๅฎไนๆบ่ฝๅ็บฆ๏ผ่ฟๆฏไบไปถๅๅๅฑไปฅๅ็งๆๆฐๆฎๅบ๏ผไธๅ้ฝๅฏไปฅๆไปถๅใ
+
+ๅ ๆญค๏ผๅณไฝฟๆจๆ้่ฆ็ๅบๅ้พๆๆฏ็ฎๅ่ฟๆฒกๆ็ธๅฏนๅบ็ๆฏๆ๏ผๆจไนไธๅฟ
ๆ
ๅฟใๆไปถๅ็่ฎพ่ฎกๅคงๅคง้ไฝไบๆทปๅ ๆดๅค็ๅบๅ้พๆๆฏ็้พๅบฆ๏ผ้ฟๅ
ไฝ ่ฑ่ดนๅคง้ๆถ้ดๅป้ๆฐๆๅปบไธๅๅบๅ้พๆๆฏไน้ดๅฏไปฅๅค็จ็ๅบ็ก่ฎพๆฝใ
+
+[](https://raw.githubusercontent.com/kaleido-io/firefly/main/doc-site/docs/images/firefly_architecture_overview.jpg)
+
+## ๅผๅงไธบ Hyperledger FireFly ๅ่ดก็ฎ
+
+ๆ ่ฎบๆจๆฏๅ็ซฏใๅ็ซฏ๏ผ่ฟๆฏๅ
จๆ ๅผๅ่
๏ผ่ฟ้้ฝๆ้ๅๆจ็่ดก็ฎๆบไผใ
+
+่ฏทๆฅ็ๆไปฌ็[่ดก็ฎ่
ๆๅ](https://hyperledger.github.io/firefly/latest/contributors/)๏ผ**ๆฌข่ฟๅ ๅ
ฅ**๏ผ
+
+## ๅ
ถไปๅญๅจๅบ
+
+ๆจๅฝๅๆๅจ็ๆฏโๆ ธๅฟโๅญๅจๅบ๏ผ็จGo่ฏญ่จ็ผๅ๏ผๅ
ๅซไบAPIๆๅกๅจๅไธญๅคฎ็ผๆๅผๆใๆฌๅบ่ฟๆไพๅค็งๆไปถๆฅๅฃ๏ผ็จไบๆฏๆไฝฟ็จ TypeScript ๅ Java ็ญ่ฏญ่จ็ผๅ็ๅพฎๆๅก่ฟๆฅๅจไปฅๅๅ
ถไปๅ
ณ้ฎ่ฟ่ก็ปไปถใ
+
+ไปฅไธๆฏๆจๅฏ่ฝๆๅ
ด่ถฃ็ๅไธชๅพฎๆๅก็ปไปถใ็จๆท็ป้ชใCLI ๅๅบ็จ็คบไพ็ๅญๅจๅบใ
+
+> ๆณจๆ๏ผไปฅไธไป
ๅๅบไบๅผๆบๅญๅจๅบๅๆไปถ
+
+### ๅบๅ้พ่ฟๆฅ
+
+- Transaction Manager๏ผๅบๅ้พไบคๆ็ฎก็็ปไปถ๏ผ- https://github.com/hyperledger/firefly-transaction-manager
+- RLP & ABI ็ผ็ , Keystore V3ๅฎ็จๅทฅๅ
ท ๅ secp256k1 ็ญพๅ่ฟ่กๆถ - https://github.com/hyperledger/firefly-signer
+- ้็จๅไปฅๅคชๅๅบๅ้พ็ๅ่่ฟๆฅๅจ - https://github.com/hyperledger/firefly-evmconnect
+ - EVMๅ
ผๅฎนๅ
ฌ้พ: ่ฏทๅ่ง[ๆๆกฃ](https://hyperledger.github.io/firefly)
+- ้ๅฏน่ฎธๅฏๅถไปฅๅคชๅๅบๅ้พ็่ฟๆฅๅจ - https://github.com/hyperledger/firefly-ethconnect
+ - ็งๆ/่ฎธๅฏๅถๅบๅ้พ: Hyperledger Besu / Quorum
+- Hyperledger Fabric่ฟๆฅๅจ - https://github.com/hyperledger/firefly-fabconnect
+- Tezos่ฟๆฅๅจ - https://github.com/hyperledger/firefly-tezosconnect
+- Corda่ฟๆฅๅจ็คบไพ: https://github.com/hyperledger/firefly-cordaconnect
+ - ไฝฟ็จ่ฏฅ่ฟๆฅๅจ๏ผ้่ฆๅฏน CorDapp ่ฟ่กๅฎๅถๅๅผๅ
+
+### ไปฃๅธๆ ๅ
+
+- ERC20/ERC721 ไปฃๅธ - https://github.com/hyperledger/firefly-tokens-erc20-erc721
+- ERC1155 ไปฃๅธ - https://github.com/hyperledger/firefly-tokens-erc1155
+
+### ็งๆๆฐๆฎๆป็บฟ่ฟๆฅ
+
+- HTTPS ๆฐๆฎไบคๆข็ปไปถ - https://github.com/hyperledger/firefly-dataexchange-https
+
+### ๅผๅ่
็ๆ็ณป็ป
+
+- ๅฝไปค่ก็้ข (CLI) - https://github.com/hyperledger/firefly-cli
+- ๅพๅฝข็จๆท็้ข - https://github.com/hyperledger/firefly-ui
+- Node.js SDK - https://github.com/hyperledger/firefly-sdk-nodejs
+- ๆฒ็/ๆต่ฏๅทฅๅ
ท - https://github.com/hyperledger/firefly-sandbox
+- ็คบไพ - https://github.com/hyperledger/firefly-samples
+- FireFly ๆง่ฝๆต่ฏ CLI: https://github.com/hyperledger/firefly-perf-cli
+- ้จ็ฝฒๅฐKubernetes็็คบไพHelm Charts: https://github.com/hyperledger/firefly-helm-charts
+
+## FireFly ๆ ธๅฟไปฃ็ ๅฑ็บง็ปๆ
+
+```
+โโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ
+โ cmd โโโโค firefly [Ff]โ - CLIๅ
ฅๅฃ
+โโโโโโโโโโโโ โ โ - ็ถ็บงไธไธๆๅๅปบ
+ โ โ - ไฟกๅทๅค็
+ โโโโโโโฌโโโโโโโโโโ
+ โ
+โโโโโโโโโโโโ โโโโโโโดโโโโโโโโโโ - HTTP ็ๅฌๅจ (Gorilla mux)
+โ internal โโโโค api [As]โ * TLS (SSL), CORS ้
็ฝฎ็ญ.
+โโโโโโโโโโโโ โ server โ * ๅไธ็ซฏๅฃไธ็ WS ๅ็บง
+ โ โ - REST ่ทฏ็ฑๅฎไน
+ โโโโโโโฌโโโโโโโโโโ * ๅช่ด่ดฃ็ฎๅ็่ทฏ็ฑ้ป่พ๏ผๆๆๅค็้ป่พไบค็ฑorchestrator
+ โ
+ โโโโโโโดโโโโโโโโโโ - REST ่ทฏ็ฑๅฎไนๆกๆถ
+ โ openapi [Oa]โ * ๆ ๅๅ Body๏ผPath๏ผQuery๏ผ Filter ่ฏญไน
+ โ spec | - ็ๆ OpenAPI 3.0 (Swagger) ๆๆกฃ
+ โโโโโโโฌโโโโโโโโโโ * ๅ
ๆฌ Swagger. UI
+ โ
+ โโโโโโโดโโโโโโโโโโ - WebSocket ๆๅกๅจ
+ โ [Ws]โ * ไธบไธๅกๅบ็จๅผๅๆไพๅผๅ่
ๅๅฅฝ็ JSON ๅ่ฎฎ
+ โ websockets โ * ๅฏ้ ็ๆๅบไบไปถไผ ้
+ โโโโโโโฌโโโโโโโโโโ * _Event interface [Ei] ๆฏๆ้ๆๅ
ถไป่ฎก็ฎๆกๆถ/ไผ ่พๆนๅผ_
+ โ
+ โโโโโโโดโโโโโโโโโโ - ็ๅฌๆฐๆฎๅบไบไปถๆนๅ็ๆๅฑๆฅๅฃ
+ โ admin [Ae]โ * ็จไบๆๅปบๅค้จ่ฟ่ก็ๅพฎๆๅกๆฉๅฑๆ ธๅฟๅ่ฝ
+ โ events | * ่ขซ Transaction Manager ็ปไปถไฝฟ็จ
+ โโโโโโโฌโโโโโโโโโโ * ๆฏๆ็นๅฎๅฏน่ฑก็ฑปๅ่ฟๆปค
+ โ
+ โโโโโโโดโโโโโโโโโโ - ๆ ธๅฟๆฐๆฎ็ฑปๅ
+ โ fftypes [Ft]โ * ็จไบ API ๅๅบๅๅ
+ โ โ * API ๅฏ้่ฟ่ทฏ็ฑๅฎไนๅฏน่พๅ
ฅๅญๆฎต่ฟ่กๅฑ่ฝ
+ โโโโโโโฌโโโโโโโโโโ
+ โ
+ โโโโโโโดโโโโโโโโโโ - ๆ ธๅฟ่ฟ่กๆถ็ฏๅขๆๅกๅจ๏ผๅๅงๅๅๆฅๆไปฅไธ็ๅฎไพ:
+ โ [Or]โ * Components๏ผๅ่ฝ็ปไปถ
+ โโโโโโโโโฌโโโโค orchestrator โ * Plugins๏ผๅฏๆๆ็ๅบ็ก่ฎพๆฝๆๅก
+ โ โ โ โ - ๅ่ทฏ็ฑๅฑๆไพๅค็้ป่พ
+ โ โ โโโโโโโโโโโโโโโโโ * ๆๆ็API่ฐ็จๅฐไผๅจ่ฟ้ๅผๅงๅค็
+ โ โ
+ โ Components: ๅ
ๅซไธป่ฆๅ่ฝ็ๅค็้ป่พ
+ โ โ
+ โ โ โโโโโโโโโโโโโโโโโ - ่ทจ้พๆๆฏๆบ่ฝๅ็บฆ้ป่พ็ๆดๅ
+ โ โโโโโค contract [Cm]โ * ไธบๆบ่ฝๅ็บฆ็ๆ OpenAPI 3 / Swagger ๅฎไน๏ผๅนถไธไผ ๆญๅฐ็ฝ็ปไธญ
+ โ โ โ manager โ * ็ฎก็ๅ็ๅบๅ้พไบไปถ็ๅฌ๏ผๅนถๅฐๅ
ถ่ทฏ็ฑๅฐๅบ็จไบไปถ
+ โ โ โโโโโโโโโโโโโโโโโ * ่ด่ดฃๅจๅ็ๅบๅ้พๆฅๅฃ (ABI ็ญ) ๅ FireFly Interface [FFI] ๆ ผๅผไน้ด็่ฝฌๆข
+ โ โ
+ โ โ โโโโโโโโโโโโโโโโโ - ็ปดๆคๆดไธช็ฝ็ป็่งๅพ
+ โ โโโโโค network [Nm]โ * ไธ network permissioning [NP] ๆไปถ็้ๆ
+ โ โ โ map โ * ไธๅนฟๆญๆไปถ็้ๆ
+ โ โ โโโโโโโโโโโโโโโโโ * ๅค็ๆๅ่บซไปฝใ่็น่บซไปฝๅ็ญพๅ่บซไปฝ็ๅฑๆฌก็ปๆ
+ โ โ
+ โ โ โโโโโโโโโโโโโโโโโ - ๅนฟๆญๆฐๆฎ็ปๆๆ็ฝ็ปไธญ็ๆๅ
+ โ โโโโโค broadcast [Bm]โ * ๅฎ็ฐๆน้็ปไปถ็ๅๅ
+ โ โ โ manager | * ไธ shared storage [Ss] ๆไปถ็้ๆ
+ โ โ โโโโโโโโโโโโโโโโโ * ไธblockchain interface [Bi] ๆไปถ็้ๆ
+ โ โ
+ โ โ โโโโโโโโโโโโโโโโโ - ๅ้็งๆๆฐๆฎ็ป็ฝ็ปไธญ็ๆๅ
+ โ โโโโโค private [Pm]โ * ๅฎ็ฐๆนๅค็็ปไปถ็่ฐๅบฆๅจ
+ โ โ โ messaging | * ไธ data exchange [Dx] ๆไปถ็้ๆ
+ โ โ โโโโโโโโฌโโโโโโโโโ * ๆถๆฏๅฏไปฅ้่ฟๅบๅ้พๅบๅฎๆ่
ๆๅบ๏ผๆ่
ไป
ๅ้
+ โ โ โ
+ โ โ โโโโโโโโดโโโโโโโโโ - ๆ็้็ฆป็ๆฐๆฎๅๅบๅ้พ็ๅๆน็พค็ป
+ โ โ โ group [Gm]โ * ไธ data exchange [Dx] ๆไปถ็้ๆ
+ โ โ โ manager โ * ไธ blockchain interface [Bi] ๆไปถ็้ๆ
+ โ โ โโโโโโโโโโโโโโโโโ
+ โ โ
+ โ โ โโโโโโโโโโโโโโโโโ - ็งๆๆฐๆฎ็ฎก็ๅ้ช่ฏ
+ โ โโโโโค data [Dm]โ * ๅฎ็ฐๆน้็ปไปถ็่ฐๅบฆๅจ
+ โ โ โ manager โ * ไธ data exchange [Dx] ๆไปถ็้ๆ
+ โ โ โโโโโโโโฌโโโโโโโโโ * ไธ blockchain interface [Bi] ๆไปถ็้ๆ
+ โ โ โ
+ โ โ โโโโโโโโดโโโโโโโโโ - JSON ๆฐๆฎๆจกๅผ็ฎก็ไธ้ช่ฏ๏ผๆถๆๅฏๆฉๅฑๅฐ XML ็ญ๏ผ
+ โ โ โ json [Jv]โ * ็ซๅ
ๅ็ซๅคๆถๆฏ็JSON่ฏญๆณ็ฎก็ๅ้ช่ฏ
+ โ โ โ validator โ * ๆจกๅผไผ ๆญ
+ โ โ โโโโโโโโฌโโโโโโโโโ * ไธๅนฟๆญๆไปถ้ๆ
+ โ โ โ
+ โ โ โโโโโโโโดโโโโโโโโโ - ๅฏ้่ฟIDๆ่
hashๅฏปๅ็ไบ่ฟๅถๆฐๆฎๅญๅจ
+ โ โ โ blobstore [Bs]โ * ไธ data exchange [Dx] ๆไปถ็้ๆ
+ โ โ โ โ * ๅฏนๆฐๆฎ่ฟ่กhashๅๅค็, ๅนถไธๅจblobๅญๅจไธญ็ปดๆค่ด่ฝฝๅผ็จ็ๆ ๅฐ
+ โ โ โโโโโโโโโโโโโโโโโ * ไธ blockchain interface [Bi] ๆไปถ็้ๆ
+ โ โ
+ โ โ โโโโโโโโโโโโโโโโโ - ่ด่ดฃๅ
ฑไบซๅญๅจๅ
ๅฎน็ไธ่ฝฝ
+ โ โโโโโค shared [Sd]โ * ๅนถ่กๅผๆญฅไธ่ฝฝ
+ โ โ โ download โ * ๅฏ้ ็้่ฏๅๅฎๆบๆขๅค
+ โ โ โโโโโโโโโโโโโโโโโ * ๅฎๆๅ้็ฅไบไปถaggregator
+ โ โ
+ โ โ โโโโโโโโโโโโโโโโโ
+ โ โโโโโค identity [Im] โ - ่ทจ็ปไปถไธญๅฟๅ่บซไปฝ็ฎก็ๆๅก
+ โ โ โ manager โ * ่งฃๆAPI่พๅ
ฅ็่บซไปฝๅๅฏ้ฅ็ปๅ๏ผไพๅฆ็ญๅ็งฐใๆ ผๅผๅ็ญ๏ผ
+ โ โ โ โ * ๅฐๆณจๅ็้พไธ็ญพๅๅฏ้ฅๆ ๅฐๅ่บซไปฝ
+ โ โ โโโโโโโโโโโโโโโโโ * ้ๆๅบๅ้พๆฅๅฃๅๅฏๆๆ่บซไปฝๆฅๅฃ๏ผๅพ
ๅฎ๏ผ
+ โ โ
+ โ โ โโโโโโโโโโโโโโโโโ - ่ฎฐๅฝ้่ฟๆไปถๅฏนๅค้จ็ปไปถๆง่ก็ๆๆๆไฝ
+ โ โโโโโค operation [Om]โ * ๆดๆฐๆฐๆฎๅบไธญ็่พๅ
ฅ/่พๅบ
+ โ โ โ manager โ * ไธบๆไปถๆไพไธ่ด็้่ฏ่ฏญไน
+ โ โ โโโโโโโโโโโโโโโโโ
+ โ โ
+ โ โ โโโโโโโโโโโโโโโโโ - ็งๆๆฐๆฎ็ฎก็ๅ้ช่ฏ
+ โ โโโโโค event [Em]โ * ๅฎ็ฐๆน้็ปไปถ็่ฐๅบฆๅจ
+ โ โ โ manager โ * ไธ data exchange [Dx] ๆไปถ็้ๆ
+ โ โ โโโโโโโโฌโโโโโโโโโ * ไธ blockchain interface [Bi] ๆไปถ็้ๆ
+ โ โ โ
+ โ โ โโโโโโโโดโโโโโโโโโ - ๅค็ไผ ๅ
ฅ็ๅค้จๆฐๆฎ
+ โ โ โ [Ag]โ * ไธ data exchange [Dx] ๆไปถ็้ๆ
+ โ โ โ aggregator โ * ไธ shared storage [Ss] ๆไปถ็้ๆ
+ โ โ โ โ * ไธ blockchain interface [Bi] ๆไปถ็้ๆ
+ โ โ โ โ - ็กฎไฟๅชๆๆๆๆฐๆฎ้ฝๅฐฑ็ปชๆถๆๆไบไปถๆไผ่ขซๅๅ
+ โ โ โโโโโโโโฌโโโโโโโโโ * ไธไธๆๆ็ฅ๏ผ้ฟๅ
โๅ
จๅฑ้ปๅกโๅบๆฏ็ๅบ็ฐ
+ โ โ โ
+ โ โ โโโโโโโโดโโโโโโโโโ - ่ฎข้
็ฎก็
+ โ โ โ [Sm]โ * ๅๅปบๅ็ฎก็่ฎข้
+ โ โ โ subscription โ * ๅๅปบๅ็ฎก็่ฎข้
+ โ โ โ manager โ * ๅๆถๆฏๅฐไบไปถๅน้
้ป่พ
+ โ โ โโโโโโโโฌโโโโโโโโโ
+ โ โ โ
+ โ โ โโโโโโโโดโโโโโโโโโ - ็ฎก็ไบไปถๅฐๅทฒ่ฟๆฅๅบ็จ็ไผ ้
+ โ โ โ event [Ed]โ * ไธ data exchange [Dx] ๆไปถ็้ๆ
+ โ โ โ dispatcher โ * ไธ blockchain interface [Bi] ๆไปถ็้ๆ
+ โ โ โโโโโโโโโโโโโโโโโ
+ โ โ
+ โ โ โโโโโโโโโโโโโโโโโ - Token ๅๅปบใไผ ่พ็ๅๅงๅใ็ดขๅผๅๅๅ
+ โ โโโโโค asset [Am]โ * ๆฏๆๅ่ดจๅไปฃๅธ๏ผๅฆๆฐๅญ่ดงๅธ๏ผ
+ โ โ โ manager โ * ๆฏๆ้ๅ่ดจๅไปฃๅธ๏ผ NFTs / globally uniqueness / digital twins
+ โ โ โโโโโโโโโโโโโโโโโ * ไบคๆๅๅฒ็ๅ
จ็ดขๅผ
+ โ โ [REST/WebSockets]
+ โ โ โโโโโโโดโโโโโโโโโโโโโโ โโโโโโโโโโโโ โโ
+ โ โ โ ERC-20 / ERC-721 โโโโโค ERC-1155 โโโโโค ๅๅปบ token ่ฟๆฅๅจ็็ฎๅๆกๆถ
+ โ โ โโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโ โโ
+ โ โ
+ โ โ โโโโโโโโโโโโโโโโโ
+ โ โโโโโค sync / [Sa] โ - ๅๆญฅใๅผๆญฅๆกฅๆฅ
+ โ โ โ async bridge โ * ๆไพๅๆญฅ่ฏทๆฑใๅบ็ญAPIs
+ โ โ โ โ * ่ฝฌๆขไธบๅบๅฑไบไปถ้ฉฑๅจAPI
+ โ โ โโโโโโโโโโโโโโโโโ
+ โ โ
+ โ โ โโโโโโโโโโโโโโโโโ - ่ๅๆฅๆๅๆฐๆฎ๏ผๅนถ็ๆๅๅธ็จไบไธ้พ
+ โ โโโโโค batch [Ba]โ * ๅฏๆๆ่ฐๅบฆๅจ
+ โ โ โ manager โ - ๆฐๆฎๅบๅไธป็บฟAPIๅค็่งฃ่ฆ
+ โ โ โ โ * ๆๅ
ณactive/activeๆๅบ็ๆดๅคไฟกๆฏ๏ผ่ฏทๅ่ๆถๆๅพ
+ โ โ โโโโโโโโฌโโโโโโโโโ - ็ฎก็ๆนๅค็ๅจๅฎไพ็ๅๅปบ
+ โ โ โ
+ โ โ โโโโโโโโดโโโโโโโโโ - ๆ นๆฎ้ๆฑๅฏๅจ็็ญ็ๅฝๅจๆไปฃ็
+ โ โ โ batch [Bp]โ * ไธไฝ่
+ๆถๆฏ็ฑปๅ่ฆๅ
+ โ โ โ processor โ - ๆน้ๆๅปบ100ๅคๆกไฟกๆฏไปฅไผๅไธ้พๆง่ฝ
+ โ โ โ โ * ่ๅๆถๆฏๅๆฐๆฎ๏ผๅนถ็ๆๅๅธ็จไบไธ้พ
+ โ โ โโโโโโโโโโโโโโโโโ - ๅจ้
็ฝฎ็็ฉบ้ฒๆถ้ดๅ่ชๅจๅ
ณ้ญ
+ โ ... ๆดๅคๅพ
ๅฎ
+ โ
+Plugins: ๆฏไธชๆไปถ้ฝๅ
ๅซไธไธชGo shim๏ผไปฅๅไธไธช่ฟ็จไปฃ็ๅพฎๆๅก่ฟ่ก็ฏๅข(ๅฆๆ้่ฆ)
+ โ
+ โ โโโโโโโโโโโโโโโโโ - ๅบๅ้พๆฅๅฃ
+ โโโโโโโโโโโโโค [Bi]โ * ไบคๆๆไบค - ๅ
ๆฌ็ญพๅๅฏ้ฅ็ฎก็
+ โ โ blockchain โ * ไบไปถ็ๅฌ
+ โ โ interface โ * ๆ ๅๅๆไฝ๏ผๅ่ชๅฎไน้พไธ่ฆๅ
+ โ โโโโโโโฌโโโโโโโโโโ
+ โ โ
+ โ โโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโฌ-โโโโโโโโโโโโโโโโโโโโ
+ โ โโโโโโโดโโโโโโโโโโ โโโโโโโโโดโโโโโโโโ โโโโโโโโโดโโโโโโโโโ โโโโโโโโโดโโโโโโโโโ
+ โ โ ethereum โ โ fabric โ โ corda/cordapps โ โ tezos โ
+ โ โโโโโโโฌโโโโโโโโโโ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโ
+ โ [REST/WebSockets]
+ โ โโโโโโโดโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโ โโ
+ โ โ transaction manager [Tm] โโโโโค Connector API [ffcapi] โโโโโค ๆๅปบๅบๅ้พ่ฟๆฅๅจ็็ฎๅๆกๆถ
+ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโ โโ
+ โ
+ โ โโโโโโโโโโโโโโโโโ - ไปฃๅธๆฅๅฃ
+ โโโโโโโโโโโโโค tokens [Ti]โ * ๆ ๅๅ็ๆ ธๅฟๆฆๅฟต๏ผtoken pools๏ผtransfers๏ผapprovals
+ โ โ interface โ * ๅฏๆๆ็่ทจไปฃๅธๆ ๅ
+ โ โโโโโโโโโโโโโโโโโ * ้่ฟๅพฎๆๅก่ฟๆฅๅจ้ๅฏน่ชๅฎไนไปฃๅธๆ ๅ็็ฎๅๅฎ็ฐๆนๅผ็ๆฏๆ
+ โ [REST/WebSockets]
+ โ โโโโโโโดโโโโโโโโโโโโโโ โโโโโโโโโโโโ โโ
+ โ โ ERC-20 / ERC-721 โโโโโค ERC-1155 โโโโโค ๆๅปบไปฃๅธ่ฟๆฅๅจ็็ฎๅๆกๆถ
+ โ โโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโ โโ
+ โ
+ โ โโโโโโโโโโโโโโโโโ - P2P ๅ
ๅฎนๅฏปๅๆไปถ็ณป็ป
+ โโโโโโโโโโโโโค shared [Si]โ * ่ด่ฝฝ ไธไผ / ไธ่ฝฝ
+ โ โ storage โ * ๆๆ็่ด่ฝฝๅ่็ฎก็
+ โ โ interface โ
+ โ โโโโโโโฌโโโโโโโโโโ
+ โ โ
+ โ โโโโโโโโโโ ... ๅฏๆๅฑ่ณไปปๆๅ
ฑไบซๅญๅจ็ณป็ป๏ผๅฏไพๆๆๆๅ่ฎฟ้ฎ
+ โ โโโโโโโดโโโโโโโโโโ
+ โ โ ipfs โ
+ โ โโโโโโโโโโโโโโโโโ
+ โ
+ โ โโโโโโโโโโโโโโโโโ - ็งๆๆฐๆฎไบคๆข
+ โโโโโโโโโโโโโค data [Dx]โ * Blob ๅญๅจ
+ โ โ exchange โ * ็งๆๅฎๅ
จๆถๆฏไผ ้
+ โ โโโโโโโฌโโโโโโโโโโ * ๅฎๅ
จ็ๆไปถไผ ่พ
+ โ โ
+ โ โโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโ ... ๅฏๆๅฑ่ณไปปๆ็งๆๆฐๆฎไบคๆขๆๆฏ
+ โ โโโโโโโดโโโโโโโโโโ โโโโโโโโโดโโโโโโโโ
+ โ โ https / MTLS โ โ Kaleido โ
+ โ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ
+ โ
+ โ โโโโโโโโโโโโโโโโโ - API ่ฎค่ฏๅ่ฎค่ฏๆฅๅฃ
+ โโโโโโโโโโโโโค api auth [Aa]โ * ้ช่ฏๅฎๅ
จๅญๆฎ (OpenID Connect id token JWTs etc.)
+ โ โ โ * ๆๅ API/user ่บซไปฝ (็จไบ่บซไปฝๆฅๅฃๆ ๅฐ)
+ โ โโโโโโโฌโโโโโโโโโโ * ็ป็ฒๅบฆ API ่ฎฟ้ฎๆงๅถ็ๆง่ก็น
+ โ โ
+ โ โโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโ ... ๅฏๆๅฑๅฐไปปๆๅ็น็ปๅฝๆๆฏ
+ โ โโโโโโโดโโโโโโโโโโ โโโโโโโโโดโโโโโโโโ
+ โ โ apikey โ โ jwt โ
+ โ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ
+ โ
+ โ โโโโโโโโโโโโโโโโโ - ๆฐๆฎๅบ้ๆ
+ โโโโโโโโโโโโโค database [Di]โ * ๅๅปบ, ่ฏปๅ, ๆดๆฐ, ๅ ้ค (CRUD) ๆไฝ
+ โ โ interface โ * ่ฟๆปคๅๆดๆฐๅฎไนๆฅๅฃ
+ โ โโโโโโโฌโโโโโโโโโโ * ่ฟ็งปๅ็ดขๅผ
+ โ โ
+ โ โโโโโโโโโโ ... ๅฏๆๅฑ่ณไปปๆNoSql (CouchDB / MongoDB etc.)
+ โ โโโโโโโดโโโโโโโโโโ
+ โ โ sqlcommon โ
+ โ โโโโโโโฌโโโโโโโโโโ
+ โ โโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโ ... ๅฏๆๅฑ่ณๅ
ถไปSQLๆฐๆฎๅบ
+ โ โโโโโโโดโโโโโโโโโโ โโโโโโโโโดโโโโโโโโโ
+ โ โ postgres โ โ sqlite3 โ
+ โ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโ
+ โ
+ โ โโโโโโโโโโโโโโโโโ - ๅฐๆ ธๅฟไบไปถๅผๆ่ฟๆฅ่ณๅค้จๆกๆถๅๅบ็จ
+ โโโโโโโโโโโโโค event [Ei]โ * ๆฏๆ้ฟๅจๆ (ๅฏๆ็ปญ็) ๅ็ญๆ็ไบไปถ่ฎข้
+ โ โ interface โ * ๆน้ใ่ฟๆปค๏ผๆๆ็ไผ ่พ้ฝไผๅจๆ ธๅฟๅบๅ่ฟ่กๅค็
+ โ โโโโโโโฌโโโโโโโโโโ * ๆฅๅฃๆฏๆ่ฟๆฅ่พๅ
ฅ (websocket) ๅ่ฟๆฅ่พๅบ (ไปฃ็่ฟ่ก็ฏๅขๆไปถ) ๆไปถ
+ โ โ
+ โ โโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโ ... ๅฏๆๅฑ่ณๅ
ถไป็ไบไปถๆป็บฟ (Kafka, NATS, AMQP etc.)
+ โ โโโโโโโดโโโโโโโโโโ โโโโโโโโโดโโโโโโโโโ
+ โ โ websockets โ โ webhooks โ
+ โ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโ
+ โ ... ๆดๅคๅพ
ๅฎ
+
+ ้ขๅค็ๅทฅๅ
ท็ฑปๆกๆถ
+ โโโโโโโโโโโโโโโโโ - REST API ๅฎขๆท็ซฏ
+ โ rest [Re]โ * ๆไพไพฟๅฉๆงๅๆฅๅฟ
+ โ client โ * ๆ ๅ็่ฎค่ฏ, ้
็ฝฎๅ้่ฏ้ป่พ
+ โโโโโโโโโโโโโโโโโ * ๆๅปบๅ้่ฏ
+
+ โโโโโโโโโโโโโโโโโ - WebSocket ๅฎขๆท็ซฏ
+ โ wsclient [Wc]โ * ๆไพไพฟๅฉๆงๅๆฅๅฟ
+ โ โ * ๆ ๅๅ่ฎค่ฏ๏ผ้
็ฝฎๅ้่ฟ้ป่พ
+ โโโโโโโโโโโโโโโโโ * ๅบไบ Gorilla WebSockets
+
+ โโโโโโโโโโโโโโโโโ - ็ฟป่ฏๆกๆถ
+ โ i18n [In]โ * ๆๆ็ฟป่ฏๅ
ๅฎนๅฟ
้กป่ฆๆทปๅ ๅฐ `en_translations.json` - ็จ `FF10101` ไฝไธบ key
+ โ โ * ้่ฏฏไผ่ขซๆๅ
, `error` ๅ
ๅ
ๆไพไบ้ขๅค็็นๆง (ๅ ๆ ็ญ.)
+ โโโโโโโโโโโโโโโโโ * ไนๆฏๆๆ่ฟฐ็ฟป่ฏ, ไพๅฆ OpenAPI ๆ่ฟฐ
+
+ โโโโโโโโโโโโโโโโโ - ๆฅๅฟๆกๆถ
+ โ log [Lo]โ * ๆฅๅฟๆกๆถ (logrus) ้ๆไบไธไธๆๆ ็ญพ
+ โ โ * ไธไธๆ่ดฏ็ฉฟๆดไธชไปฃ็ ๏ผ็จไบไผ ้API่ฐ็จไธไธๆไปฅๅๆฅๅฟไธไธๆ
+ โโโโโโโโโโโโโโโโโ * ๆ ทไพ: ๆๆ็API่ฐ็จ้ฝๆ็ๅฏ่ฟฝๆบฏID, ไปฅๅๆถ้ฟ
+
+ โโโโโโโโโโโโโโโโโ - ้
็ฝฎ
+ โ config [Co]โ * ๅบไบๆฅๅฟๆกๆถ็ๆไปถๅ็ฏๅขๅ้ (viper)
+ โ โ * ไธป่ฆ้
็ฝฎkeyๅ
จ้จ้ไธญๅฎไน
+ โโโโโโโโโโโโโโโโโ * ๆไปถ้่ฟ่ฟๅๅ
ถ้
็ฝฎ็ปๆ่ฟ่ก้ๆ (JSON ๆ ็ญพ)
+
+```
diff --git a/auditevents/main.go b/auditevents/main.go
index 3f3b155a9e..41265f5ebe 100644
--- a/auditevents/main.go
+++ b/auditevents/main.go
@@ -18,6 +18,7 @@ package main
import (
"encoding/json"
+ "errors"
"fmt"
"io"
"net/http"
@@ -94,7 +95,7 @@ func run(host string) error {
protocolID := event.BlockchainEvent.ProtocolID
fmt.Printf("%-10d %s\n", lastSequence, protocolID)
if protocolID <= lastProtocolID {
- return fmt.Errorf("out of order events detected")
+ return errors.New("out of order events detected")
}
lastProtocolID = protocolID
validated++
diff --git a/doc-site/.github/workflows/ci.yml b/doc-site/.github/workflows/ci.yml
index ddff3e16ed..e24cd9fa52 100644
--- a/doc-site/.github/workflows/ci.yml
+++ b/doc-site/.github/workflows/ci.yml
@@ -23,7 +23,7 @@ jobs:
- uses: actions/setup-python@v4
with:
python-version: 3.x
- - uses: actions/cache@v2
+ - uses: actions/cache@v4
with:
key: ${{ github.ref }}
path: .cache
diff --git a/doc-site/docs/SUMMARY.md b/doc-site/docs/SUMMARY.md
index cb5d3eb3eb..e93f3798f1 100644
--- a/doc-site/docs/SUMMARY.md
+++ b/doc-site/docs/SUMMARY.md
@@ -28,5 +28,7 @@
* contributors/*
* [API Spec](swagger/index.md)
* [FAQs](faqs/index.md)
+* [Troubleshooting](troubleshooting/index.md)
+ * troubleshooting/*
* [Release Notes](releasenotes/index.md)
* releasenotes/*
\ No newline at end of file
diff --git a/doc-site/docs/gettingstarted/setup_env.md b/doc-site/docs/gettingstarted/setup_env.md
index 95e7baffcf..cd48aa706a 100644
--- a/doc-site/docs/gettingstarted/setup_env.md
+++ b/doc-site/docs/gettingstarted/setup_env.md
@@ -84,7 +84,7 @@ Global Flags:
-d, --database string Database type to use. Options are: [sqlite3 postgres] (default "sqlite3")
-e, --external int Manage a number of FireFly core processes outside of the docker-compose stack - useful for development and debugging
-p, --firefly-base-port int Mapped port base of FireFly core API (1 added for each member) (default 5000)
- --ipfs-mode string Set the mode in which IFPS operates. Options are: [private public] (default "private")
+ --ipfs-mode string Set the mode in which IPFS operates. Options are: [private public] (default "private")
-m, --manifest string Path to a manifest.json file containing the versions of each FireFly microservice to use. Overrides the --release flag.
--multiparty Enable or disable multiparty mode (default true)
--node-name stringArray Node name
diff --git a/doc-site/docs/images/firefly_message_types.png b/doc-site/docs/images/firefly_message_types.png
new file mode 100644
index 0000000000..0da0133777
Binary files /dev/null and b/doc-site/docs/images/firefly_message_types.png differ
diff --git a/doc-site/docs/images/smart_contracts_async_flow.svg b/doc-site/docs/images/smart_contracts_async_flow.svg
index 89634efa79..c4157d8311 100644
--- a/doc-site/docs/images/smart_contracts_async_flow.svg
+++ b/doc-site/docs/images/smart_contracts_async_flow.svg
@@ -1 +1,95 @@
-
\ No newline at end of file
+
+
diff --git a/doc-site/docs/reference/config.md b/doc-site/docs/reference/config.md
index 82b7f3ef43..f34c16c81f 100644
--- a/doc-site/docs/reference/config.md
+++ b/doc-site/docs/reference/config.md
@@ -264,6 +264,7 @@ title: Configuration Reference
|idleTimeout|The max duration to hold a HTTP keepalive connection between calls|[`time.Duration`](https://pkg.go.dev/time#Duration)|`475ms`
|maxConnsPerHost|The max number of connections, per unique hostname. Zero means no limit|`int`|`0`
|maxIdleConns|The max number of idle connections to hold pooled|`int`|`100`
+|maxIdleConnsPerHost|The max number of idle connections, per unique hostname. Zero means net/http uses the default of only 2.|`int`|`100`
|passthroughHeadersEnabled|Enable passing through the set of allowed HTTP request headers|`boolean`|`false`
|requestTimeout|The maximum amount of time that a request is allowed to remain open|[`time.Duration`](https://pkg.go.dev/time#Duration)|`30s`
|tlsHandshakeTimeout|The maximum amount of time to wait for a successful TLS handshake|[`time.Duration`](https://pkg.go.dev/time#Duration)|`10s`
@@ -406,30 +407,70 @@ title: Configuration Reference
## metrics
+|Key|Description|Type|Default Value|
+|---|-----------|----|-------------|
+|address|Deprecated - use monitoring.address instead|`int`|`127.0.0.1`
+|enabled|Deprecated - use monitoring.enabled instead|`boolean`|`true`
+|path|Deprecated - use monitoring.metricsPath instead|`string`|`/metrics`
+|port|Deprecated - use monitoring.port instead|`int`|`6000`
+|publicURL|Deprecated - use monitoring.publicURL instead|URL `string`|``
+|readTimeout|Deprecated - use monitoring.readTimeout instead|[`time.Duration`](https://pkg.go.dev/time#Duration)|`15s`
+|shutdownTimeout|The maximum amount of time to wait for any open HTTP requests to finish before shutting down the HTTP server|[`time.Duration`](https://pkg.go.dev/time#Duration)|`10s`
+|writeTimeout|Deprecated - use monitoring.writeTimeout instead|[`time.Duration`](https://pkg.go.dev/time#Duration)|`15s`
+
+## metrics.auth
+
+|Key|Description|Type|Default Value|
+|---|-----------|----|-------------|
+|type|The auth plugin to use for server side authentication of requests|`string`|``
+
+## metrics.auth.basic
+
+|Key|Description|Type|Default Value|
+|---|-----------|----|-------------|
+|passwordfile|The path to a .htpasswd file to use for authenticating requests. Passwords should be hashed with bcrypt.|`string`|``
+
+## metrics.tls
+
+|Key|Description|Type|Default Value|
+|---|-----------|----|-------------|
+|ca|The TLS certificate authority in PEM format (this option is ignored if caFile is also set)|`string`|``
+|caFile|The path to the CA file for TLS on this API|`string`|``
+|cert|The TLS certificate in PEM format (this option is ignored if certFile is also set)|`string`|``
+|certFile|The path to the certificate file for TLS on this API|`string`|``
+|clientAuth|Enables or disables client auth for TLS on this API|`string`|``
+|enabled|Enables or disables TLS on this API|`boolean`|`false`
+|insecureSkipHostVerify|When to true in unit test development environments to disable TLS verification. Use with extreme caution|`boolean`|``
+|key|The TLS certificate key in PEM format (this option is ignored if keyFile is also set)|`string`|``
+|keyFile|The path to the private key file for TLS on this API|`string`|``
+|requiredDNAttributes|A set of required subject DN attributes. Each entry is a regular expression, and the subject certificate must have a matching attribute of the specified type (CN, C, O, OU, ST, L, STREET, POSTALCODE, SERIALNUMBER are valid attributes)|`map[string]string`|``
+
+## monitoring
+
|Key|Description|Type|Default Value|
|---|-----------|----|-------------|
|address|The IP address on which the metrics HTTP API should listen|`int`|`127.0.0.1`
-|enabled|Enables the metrics API|`boolean`|`true`
-|path|The path from which to serve the Prometheus metrics|`string`|`/metrics`
+|enabled|Enables the metrics API|`boolean`|`false`
+|metricsPath|The path from which to serve the Prometheus metrics|`string`|`/metrics`
|port|The port on which the metrics HTTP API should listen|`int`|`6000`
|publicURL|The fully qualified public URL for the metrics API. This is used for building URLs in HTTP responses and in OpenAPI Spec generation|URL `string`|``
|readTimeout|The maximum time to wait when reading from an HTTP connection|[`time.Duration`](https://pkg.go.dev/time#Duration)|`15s`
|shutdownTimeout|The maximum amount of time to wait for any open HTTP requests to finish before shutting down the HTTP server|[`time.Duration`](https://pkg.go.dev/time#Duration)|`10s`
|writeTimeout|The maximum time to wait when writing to an HTTP connection|[`time.Duration`](https://pkg.go.dev/time#Duration)|`15s`
-## metrics.auth
+## monitoring.auth
|Key|Description|Type|Default Value|
|---|-----------|----|-------------|
|type|The auth plugin to use for server side authentication of requests|`string`|``
-## metrics.auth.basic
+## monitoring.auth.basic
|Key|Description|Type|Default Value|
|---|-----------|----|-------------|
|passwordfile|The path to a .htpasswd file to use for authenticating requests. Passwords should be hashed with bcrypt.|`string`|``
-## metrics.tls
+## monitoring.tls
|Key|Description|Type|Default Value|
|---|-----------|----|-------------|
@@ -607,6 +648,7 @@ title: Configuration Reference
|idleTimeout|The max duration to hold a HTTP keepalive connection between calls|[`time.Duration`](https://pkg.go.dev/time#Duration)|`475ms`
|maxConnsPerHost|The max number of connections, per unique hostname. Zero means no limit|`int`|`0`
|maxIdleConns|The max number of idle connections to hold pooled|`int`|`100`
+|maxIdleConnsPerHost|The max number of idle connections, per unique hostname. Zero means net/http uses the default of only 2.|`int`|`100`
|method|The HTTP method to use when making requests to the Address Resolver|`string`|`GET`
|passthroughHeadersEnabled|Enable passing through the set of allowed HTTP request headers|`boolean`|`false`
|requestTimeout|The maximum amount of time that a request is allowed to remain open|[`time.Duration`](https://pkg.go.dev/time#Duration)|`30s`
@@ -675,6 +717,7 @@ title: Configuration Reference
|instance|The Ethereum address of the FireFly BatchPin smart contract that has been deployed to the blockchain|Address `string`|``
|maxConnsPerHost|The max number of connections, per unique hostname. Zero means no limit|`int`|`0`
|maxIdleConns|The max number of idle connections to hold pooled|`int`|`100`
+|maxIdleConnsPerHost|The max number of idle connections, per unique hostname. Zero means net/http uses the default of only 2.|`int`|`100`
|passthroughHeadersEnabled|Enable passing through the set of allowed HTTP request headers|`boolean`|`false`
|prefixLong|The prefix that will be used for Ethconnect specific HTTP headers when FireFly makes requests to Ethconnect|`string`|`firefly`
|prefixShort|The prefix that will be used for Ethconnect specific query parameters when FireFly makes requests to Ethconnect|`string`|`fly`
@@ -759,6 +802,7 @@ title: Configuration Reference
|idleTimeout|The max duration to hold a HTTP keepalive connection between calls|[`time.Duration`](https://pkg.go.dev/time#Duration)|`475ms`
|maxConnsPerHost|The max number of connections, per unique hostname. Zero means no limit|`int`|`0`
|maxIdleConns|The max number of idle connections to hold pooled|`int`|`100`
+|maxIdleConnsPerHost|The max number of idle connections, per unique hostname. Zero means net/http uses the default of only 2.|`int`|`100`
|passthroughHeadersEnabled|Enable passing through the set of allowed HTTP request headers|`boolean`|`false`
|requestTimeout|The maximum amount of time that a request is allowed to remain open|[`time.Duration`](https://pkg.go.dev/time#Duration)|`30s`
|tlsHandshakeTimeout|The maximum amount of time to wait for a successful TLS handshake|[`time.Duration`](https://pkg.go.dev/time#Duration)|`10s`
@@ -823,6 +867,7 @@ title: Configuration Reference
|idleTimeout|The max duration to hold a HTTP keepalive connection between calls|[`time.Duration`](https://pkg.go.dev/time#Duration)|`475ms`
|maxConnsPerHost|The max number of connections, per unique hostname. Zero means no limit|`int`|`0`
|maxIdleConns|The max number of idle connections to hold pooled|`int`|`100`
+|maxIdleConnsPerHost|The max number of idle connections, per unique hostname. Zero means net/http uses the default of only 2.|`int`|`100`
|passthroughHeadersEnabled|Enable passing through the set of allowed HTTP request headers|`boolean`|`false`
|prefixLong|The prefix that will be used for Fabconnect specific HTTP headers when FireFly makes requests to Fabconnect|`string`|`firefly`
|prefixShort|The prefix that will be used for Fabconnect specific query parameters when FireFly makes requests to Fabconnect|`string`|`fly`
@@ -910,6 +955,7 @@ title: Configuration Reference
|idleTimeout|The max duration to hold a HTTP keepalive connection between calls|[`time.Duration`](https://pkg.go.dev/time#Duration)|`475ms`
|maxConnsPerHost|The max number of connections, per unique hostname. Zero means no limit|`int`|`0`
|maxIdleConns|The max number of idle connections to hold pooled|`int`|`100`
+|maxIdleConnsPerHost|The max number of idle connections, per unique hostname. Zero means net/http uses the default of only 2.|`int`|`100`
|method|The HTTP method to use when making requests to the Address Resolver|`string`|`GET`
|passthroughHeadersEnabled|Enable passing through the set of allowed HTTP request headers|`boolean`|`false`
|requestTimeout|The maximum amount of time that a request is allowed to remain open|[`time.Duration`](https://pkg.go.dev/time#Duration)|`30s`
@@ -976,6 +1022,7 @@ title: Configuration Reference
|idleTimeout|The max duration to hold a HTTP keepalive connection between calls|[`time.Duration`](https://pkg.go.dev/time#Duration)|`475ms`
|maxConnsPerHost|The max number of connections, per unique hostname. Zero means no limit|`int`|`0`
|maxIdleConns|The max number of idle connections to hold pooled|`int`|`100`
+|maxIdleConnsPerHost|The max number of idle connections, per unique hostname. Zero means net/http uses the default of only 2.|`int`|`100`
|passthroughHeadersEnabled|Enable passing through the set of allowed HTTP request headers|`boolean`|`false`
|prefixLong|The prefix that will be used for Tezosconnect specific HTTP headers when FireFly makes requests to Tezosconnect|`string`|`firefly`
|prefixShort|The prefix that will be used for Tezosconnect specific query parameters when FireFly makes requests to Tezosconnect|`string`|`fly`
@@ -1110,6 +1157,7 @@ title: Configuration Reference
|manifestEnabled|Determines whether to require+validate a manifest from other DX instances in the network. Must be supported by the connector|`string`|`false`
|maxConnsPerHost|The max number of connections, per unique hostname. Zero means no limit|`int`|`0`
|maxIdleConns|The max number of idle connections to hold pooled|`int`|`100`
+|maxIdleConnsPerHost|The max number of idle connections, per unique hostname. Zero means net/http uses the default of only 2.|`int`|`100`
|passthroughHeadersEnabled|Enable passing through the set of allowed HTTP request headers|`boolean`|`false`
|requestTimeout|The maximum amount of time that a request is allowed to remain open|[`time.Duration`](https://pkg.go.dev/time#Duration)|`30s`
|tlsHandshakeTimeout|The maximum amount of time to wait for a successful TLS handshake|[`time.Duration`](https://pkg.go.dev/time#Duration)|`10s`
@@ -1213,6 +1261,7 @@ title: Configuration Reference
|idleTimeout|The max duration to hold a HTTP keepalive connection between calls|[`time.Duration`](https://pkg.go.dev/time#Duration)|`475ms`
|maxConnsPerHost|The max number of connections, per unique hostname. Zero means no limit|`int`|`0`
|maxIdleConns|The max number of idle connections to hold pooled|`int`|`100`
+|maxIdleConnsPerHost|The max number of idle connections, per unique hostname. Zero means net/http uses the default of only 2.|`int`|`100`
|passthroughHeadersEnabled|Enable passing through the set of allowed HTTP request headers|`boolean`|`false`
|requestTimeout|The maximum amount of time that a request is allowed to remain open|[`time.Duration`](https://pkg.go.dev/time#Duration)|`30s`
|tlsHandshakeTimeout|The maximum amount of time to wait for a successful TLS handshake|[`time.Duration`](https://pkg.go.dev/time#Duration)|`10s`
@@ -1273,6 +1322,7 @@ title: Configuration Reference
|idleTimeout|The max duration to hold a HTTP keepalive connection between calls|[`time.Duration`](https://pkg.go.dev/time#Duration)|`475ms`
|maxConnsPerHost|The max number of connections, per unique hostname. Zero means no limit|`int`|`0`
|maxIdleConns|The max number of idle connections to hold pooled|`int`|`100`
+|maxIdleConnsPerHost|The max number of idle connections, per unique hostname. Zero means net/http uses the default of only 2.|`int`|`100`
|passthroughHeadersEnabled|Enable passing through the set of allowed HTTP request headers|`boolean`|`false`
|requestTimeout|The maximum amount of time that a request is allowed to remain open|[`time.Duration`](https://pkg.go.dev/time#Duration)|`30s`
|tlsHandshakeTimeout|The maximum amount of time to wait for a successful TLS handshake|[`time.Duration`](https://pkg.go.dev/time#Duration)|`10s`
@@ -1341,6 +1391,7 @@ title: Configuration Reference
|idleTimeout|The max duration to hold a HTTP keepalive connection between calls|[`time.Duration`](https://pkg.go.dev/time#Duration)|`475ms`
|maxConnsPerHost|The max number of connections, per unique hostname. Zero means no limit|`int`|`0`
|maxIdleConns|The max number of idle connections to hold pooled|`int`|`100`
+|maxIdleConnsPerHost|The max number of idle connections, per unique hostname. Zero means net/http uses the default of only 2.|`int`|`100`
|passthroughHeadersEnabled|Enable passing through the set of allowed HTTP request headers|`boolean`|`false`
|requestTimeout|The maximum amount of time that a request is allowed to remain open|[`time.Duration`](https://pkg.go.dev/time#Duration)|`30s`
|tlsHandshakeTimeout|The maximum amount of time to wait for a successful TLS handshake|[`time.Duration`](https://pkg.go.dev/time#Duration)|`10s`
diff --git a/doc-site/docs/reference/firefly_interface_format.md b/doc-site/docs/reference/firefly_interface_format.md
index e9d1238564..9370b609cf 100644
--- a/doc-site/docs/reference/firefly_interface_format.md
+++ b/doc-site/docs/reference/firefly_interface_format.md
@@ -98,7 +98,7 @@ For example, the Ethereum plugin always needs to know what Solidity type the fie
## Automated generation of FireFly Interfaces
-A convenience endpoint exists on the API to facilitate converting from native blockchain interface formats such as an Ethereum ABI to the FireFly Interface format. For details, please see the API documentation for the contract interface generation endpoint.
+A convenience endpoint exists on the API to facilitate converting from native blockchain interface formats such as an Ethereum ABI to the FireFly Interface format. For details, please see the API documentation for the contract interface generation endpoint.
For an example of using this endpoint with a specific Ethereum contract, please see the [Tutorial to Work with custom smart contracts](../tutorials/custom_contracts/index.md).
diff --git a/doc-site/docs/reference/types/_includes/contractlistener_description.md b/doc-site/docs/reference/types/_includes/contractlistener_description.md
index 5027b71ade..d9071511eb 100644
--- a/doc-site/docs/reference/types/_includes/contractlistener_description.md
+++ b/doc-site/docs/reference/types/_includes/contractlistener_description.md
@@ -40,7 +40,7 @@ Each filter is identified by a generated `signature` that matches a single event
Ethereum provides a string standard for event signatures, of the form `EventName(uint256,bytes)`. Prior to v1.3.1, the signature of each Ethereum contract listener would exactly follow this Ethereum format.
-As of v1.3.1, Ethereum signature strings have been changed, because this format does not fully describe the event - particularly because each top-level parameter can in the ABI definition be marked as `indexed`. For example, while the following two Solidity events have the same signature, they are serialized differently due to the different placement of `indexed` parameters, and thus a listener must define both individually to be able to process them:
+As of v1.3.1, Ethereum format signature strings have been changed in FireFly, because this format does not fully describe the event - particularly because each top-level parameter can in the ABI definition be marked as `indexed`. For example, while the following two Solidity events have the same signature, they are serialized differently due to the different placement of `indexed` parameters, and thus a listener must define both individually to be able to process them:
- ERC-20 `Transfer`
@@ -54,7 +54,7 @@ As of v1.3.1, Ethereum signature strings have been changed, because this format
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
```
-The two above are now expressed in the following manner by the Ethereum blockchain connector:
+The two above are now expressed in the following manner by the FireFly Ethereum blockchain connector:
```solidity
Transfer(address,address,uint256) [i=0,1]
@@ -65,7 +65,7 @@ The `[i=]` listing at the end of the signature indicates the position of all par
Building on the blockchain-specific signature format for each event, FireFly will then compute the final signature for each filter and each contract listener as follows:
-- Each filter signature is a combination of the location and the specific connector event signature, such as `0xa5ea5d0a6b2eaf194716f0cc73981939dca26da1:Changed(address,uint256) [i=0]`
+- Each filter signature is a combination of the location and the specific connector event signature, such as `0xa5ea5d0a6b2eaf194716f0cc73981939dca26da1:Transfer(address,address,uint256) [i=0,1]`
- Each contract listener signature is a concatenation of all the filter signatures, separated by `;`
#### Duplicate filters
@@ -84,7 +84,7 @@ As noted above, each listener has a generated signature. This signature - contai
### Backwards compatibility
-As noted throughout this document, the behavior of listeners is changed in v1.3.1. However, the following behaviors are retained for backwards-compatibility, to ensure that code written prior to v1.3.1 should continue to function.
+As noted throughout this document, the behavior of listeners has changed in v1.3.1. However, the following behaviors are retained for backwards-compatibility, to ensure that code written prior to v1.3.1 should continue to function.
- The response from all query APIs of `listeners` will continue to populate top-level `event` and `location` fields
- The first entry from the `filters` array is duplicated to these fields
@@ -93,12 +93,104 @@ As noted throughout this document, the behavior of listeners is changed in v1.3.
- The `signature` field is preserved at the listener level
- The format has been changed as described above
-### Input formats
+## Input examples
The two input formats supported when creating a contract listener are shown below.
+### With event definition
+
+In these examples, the event schema in the FireFly Interface format is provided describing the event and its parameters. See [FireFly Interface Format](../firefly_interface_format.md)
+
**Muliple Filters**
+```json
+{
+ "filters": [
+ {
+ "event": {
+ "name": "Changed",
+ "description": "",
+ "params": [
+ {
+ "name": "x",
+ "schema": {
+ "type": "integer",
+ "details": {
+ "type": "uint256",
+ "internalType": "uint256"
+ }
+ }
+ }
+ ]
+ },
+ "location": {
+ "address": "0xa5ea5d0a6b2eaf194716f0cc73981939dca26da1"
+ }
+ },
+ {
+ "event": {
+ "name": "AnotherEvent",
+ "description": "",
+ "params": [
+ {
+ "name": "my-field",
+ "schema": {
+ "type": "string",
+ "details": {
+ "type": "address",
+ "internalType": "address",
+ "indexed": true
+ }
+ }
+ }
+ ]
+ },
+ "location": {
+ "address": "0xa4ea5d0b6b2eaf194716f0cc73981939dca27da1"
+ }
+ }
+ ],
+ "options": {
+ "firstEvent": "newest"
+ },
+ "topic": "simple-storage"
+}
+```
+
+**One filter (old format)**
+
+```json
+{
+ "event": {
+ "name": "Changed",
+ "description": "",
+ "params": [
+ {
+ "name": "x",
+ "schema": {
+ "type": "integer",
+ "details": {
+ "type": "uint256",
+ "internalType": "uint256"
+ }
+ }
+ }
+ ]
+ },
+ "location": {
+ "address": "0xa5ea5d0a6b2eaf194716f0cc73981939dca26da1"
+ },
+ "options": {
+ "firstEvent": "newest"
+ },
+ "topic": "simple-storage"
+}
+```
+
+### With interface reference
+These examples use an `interface` reference when creating the filters, the `eventPath` field is used to reference an event defined within the interface provided. In this case, we do not need to provide the event schema as the section above shows. See an example of creating a [FireFly Interface](../../tutorials/custom_contracts/ethereum.md/#the-firefly-interface-format) for an EVM smart contract.
+
+**Muliple Filters**
```json
{
"filters": [
diff --git a/doc-site/docs/reference/types/contractlistener.md b/doc-site/docs/reference/types/contractlistener.md
index 9b5b13415a..f46e78186e 100644
--- a/doc-site/docs/reference/types/contractlistener.md
+++ b/doc-site/docs/reference/types/contractlistener.md
@@ -121,9 +121,9 @@ title: ContractListener
| Field Name | Description | Type |
|------------|-------------|------|
-| `event` | The definition of the event, either provided in-line when creating the listener, or extracted from the referenced FFI | [`FFISerializedEvent`](#ffiserializedevent) |
+| `event` | The definition of the event, either provided in-line when creating the listener, or extracted from the referenced FFI when supplied | [`FFISerializedEvent`](#ffiserializedevent) |
| `location` | A blockchain specific contract identifier. For example an Ethereum contract address, or a Fabric chaincode name and channel | [`JSONAny`](simpletypes.md#jsonany) |
-| `interface` | A reference to an existing FFI, containing pre-registered type information for the event | [`FFIReference`](#ffireference) |
+| `interface` | A reference to an existing FFI, containing pre-registered type information for the event, used in combination with eventPath | [`FFIReference`](#ffireference) |
| `signature` | The stringified signature of the event and location, as computed by the blockchain plugin | `string` |
diff --git a/doc-site/docs/reference/types/subscription.md b/doc-site/docs/reference/types/subscription.md
index d6a8767ccb..903cf0d93f 100644
--- a/doc-site/docs/reference/types/subscription.md
+++ b/doc-site/docs/reference/types/subscription.md
@@ -86,7 +86,7 @@ title: Subscription
| Field Name | Description | Type |
|------------|-------------|------|
| `firstEvent` | Whether your application would like to receive events from the 'oldest' event emitted by your FireFly node (from the beginning of time), or the 'newest' event (from now), or a specific event sequence. Default is 'newest' | `SubOptsFirstEvent` |
-| `readAhead` | The number of events to stream ahead to your application, while waiting for confirmation of consumption of those events. At least once delivery semantics are used in FireFly, so if your application crashes/reconnects this is the maximum number of events you would expect to be redelivered after it restarts | `uint16` |
+| `readAhead` | The number of events to stream ahead to your application, while waiting for confirmation of consumption of those events. At least once delivery semantics are used in FireFly, so if your application crashes/reconnects this is the maximum number of events you would expect to be redelivered after it restarts | `uint` |
| `withData` | Whether message events delivered over the subscription, should be packaged with the full data of those messages in-line as part of the event JSON payload. Or if the application should make separate REST calls to download that data. May not be supported on some transports. | `bool` |
| `batch` | Events are delivered in batches in an ordered array. The batch size is capped to the readAhead limit. The event payload is always an array even if there is a single event in the batch, allowing client-side optimizations when processing the events in a group. Available for both Webhooks and WebSockets. | `bool` |
| `batchTimeout` | When batching is enabled, the optional timeout to send events even when the batch hasn't filled. | `string` |
diff --git a/doc-site/docs/reference/types/wsstart.md b/doc-site/docs/reference/types/wsstart.md
index 9c674338b4..07e3f3223f 100644
--- a/doc-site/docs/reference/types/wsstart.md
+++ b/doc-site/docs/reference/types/wsstart.md
@@ -77,7 +77,7 @@ title: WSStart
| Field Name | Description | Type |
|------------|-------------|------|
| `firstEvent` | Whether your application would like to receive events from the 'oldest' event emitted by your FireFly node (from the beginning of time), or the 'newest' event (from now), or a specific event sequence. Default is 'newest' | `SubOptsFirstEvent` |
-| `readAhead` | The number of events to stream ahead to your application, while waiting for confirmation of consumption of those events. At least once delivery semantics are used in FireFly, so if your application crashes/reconnects this is the maximum number of events you would expect to be redelivered after it restarts | `uint16` |
+| `readAhead` | The number of events to stream ahead to your application, while waiting for confirmation of consumption of those events. At least once delivery semantics are used in FireFly, so if your application crashes/reconnects this is the maximum number of events you would expect to be redelivered after it restarts | `uint` |
| `withData` | Whether message events delivered over the subscription, should be packaged with the full data of those messages in-line as part of the event JSON payload. Or if the application should make separate REST calls to download that data. May not be supported on some transports. | `bool` |
| `batch` | Events are delivered in batches in an ordered array. The batch size is capped to the readAhead limit. The event payload is always an array even if there is a single event in the batch, allowing client-side optimizations when processing the events in a group. Available for both Webhooks and WebSockets. | `bool` |
| `batchTimeout` | When batching is enabled, the optional timeout to send events even when the batch hasn't filled. | `string` |
diff --git a/doc-site/docs/releasenotes/index.md b/doc-site/docs/releasenotes/index.md
index 9e8eddb499..1c9a19473f 100644
--- a/doc-site/docs/releasenotes/index.md
+++ b/doc-site/docs/releasenotes/index.md
@@ -2,8 +2,35 @@
title: Release Notes
---
+# Release Notes
+
[Full release notes](https://github.com/hyperledger/firefly/releases)
+## [v1.3.3 - Mar 25, 2025](https://github.com/hyperledger/firefly/releases/tag/v1.3.3)
+
+What's New:
+- Add new interface for blockchain plugins to stream receipt notifications in transactional batches
+ - For blockchain connectors that have an `ack` based reliable receipt stream (or other checkpoint system)
+ - Allows strictly ordered delivery of receipts from blockchain plugins that support it
+ - Allows resilience on receipt delivery to core, against a checkpoint maintained in the connector
+- Changes in metrics:
+ - Added new metrics for Data Exchange for monitoring by a timeseries and alerting system.
+ - `ff_multiparty_node_identity_dx_mismatch` notify that the certificate in FireFly Core is different to the one stored in Data Exchange
+ - `ff_multiparty_node_identity_dx_expiry_epoch` emit the timestamp of the certificate of Data Exchange useful for SREs to monitor before it expires
+ - Added a namespace label to existing metrics to separate metrics more easily
+ - Added HTTP Response Time and Complete Gauge Support to `firefly-common`
+ - Allow the `metrics` server to host additional routes such as status endpoints
+ - This resulted in a new configuration section of `monitoring` to be more appropriate than `metrics` which has now be deprecated.
+- Fix to issue that resulted in retried private messages using local namespace rather than the network namespace
+- Fix to issue that could result in messages being marked `Pending` on re-delivery of a batch over the network
+- Miscellaneous bug fixes and minor improvements
+- Documentation updates, new troubleshooting section for multiparty messages
+- CVE fixes and adoption of OpenSSF scorecard on key repositories
+
+### Migration consideration
+
+As part of the changes to the metrics to add the new `namespace` label, we changed from using a Prometheus `Counter` to a `CounterVec`. As a result there is no default value of `0` on the counter, which means when users query for a specific metric such as `ff_message_rejected_total` it will not be available until the `CounterVec` associated with that metric is incremented. This has been determined to be an easy upgrade for SRE monitoring these metrics, hence inclusion in a patch release.
+
## [v1.3.2 - Oct 3, 2024](https://github.com/hyperledger/firefly/releases/tag/v1.3.2)
What's New:
@@ -24,7 +51,7 @@ What's New:
See [Contract Listeners](../reference/types/contractlistener.md) for details
- New multiparty status API at `/status/multiparty`
-## [v1.3.0 - April 25, 2024](https://github.com/hyperledger/firefly/releases/tag/v1.1.0)
+## [v1.3.0 - April 25, 2024](https://github.com/hyperledger/firefly/releases/tag/v1.3.0)
[Migration guide](1.3_migration_guide.md)
@@ -50,9 +77,6 @@ What's New:
- Custom HTTP headers can be passed through to FireFly dependency microservices
- Evmconnect is now the default blockchain connector for Ethereum based FireFly stacks
-# Release Notes
-
-[Full release notes](https://github.com/hyperledger/firefly/releases)
## [v1.1.0 - September 12, 2022](https://github.com/hyperledger/firefly/releases/tag/v1.1.0)
diff --git a/doc-site/docs/swagger/swagger.yaml b/doc-site/docs/swagger/swagger.yaml
index 60a2e7b24d..cfac89b6bb 100644
--- a/doc-site/docs/swagger/swagger.yaml
+++ b/doc-site/docs/swagger/swagger.yaml
@@ -1443,7 +1443,7 @@ paths:
event:
description: The definition of the event, either provided
in-line when creating the listener, or extracted from
- the referenced FFI
+ the referenced FFI when supplied
properties:
description:
description: A description of the smart contract event
@@ -1487,7 +1487,8 @@ paths:
type: object
interface:
description: A reference to an existing FFI, containing
- pre-registered type information for the event
+ pre-registered type information for the event, used
+ in combination with eventPath
properties:
id:
description: The UUID of the FireFly interface
@@ -1725,7 +1726,7 @@ paths:
event:
description: The definition of the event, either provided
in-line when creating the listener, or extracted from
- the referenced FFI
+ the referenced FFI when supplied
properties:
description:
description: A description of the smart contract event
@@ -1767,7 +1768,8 @@ paths:
type: object
interface:
description: A reference to an existing FFI, containing
- pre-registered type information for the event
+ pre-registered type information for the event, used in
+ combination with eventPath
properties:
id:
description: The UUID of the FireFly interface
@@ -5885,7 +5887,7 @@ paths:
event:
description: The definition of the event, either provided
in-line when creating the listener, or extracted from
- the referenced FFI
+ the referenced FFI when supplied
properties:
description:
description: A description of the smart contract event
@@ -5929,7 +5931,8 @@ paths:
type: object
interface:
description: A reference to an existing FFI, containing
- pre-registered type information for the event
+ pre-registered type information for the event, used
+ in combination with eventPath
properties:
id:
description: The UUID of the FireFly interface
@@ -6082,7 +6085,7 @@ paths:
event:
description: The definition of the event, either provided
in-line when creating the listener, or extracted from the
- referenced FFI
+ referenced FFI when supplied
properties:
description:
description: A description of the smart contract event
@@ -6127,7 +6130,8 @@ paths:
type: string
interface:
description: A reference to an existing FFI, containing pre-registered
- type information for the event
+ type information for the event, used in combination with
+ eventPath
properties:
id:
description: The UUID of the FireFly interface
@@ -6251,7 +6255,7 @@ paths:
event:
description: The definition of the event, either provided
in-line when creating the listener, or extracted from
- the referenced FFI
+ the referenced FFI when supplied
properties:
description:
description: A description of the smart contract event
@@ -6293,7 +6297,8 @@ paths:
type: object
interface:
description: A reference to an existing FFI, containing
- pre-registered type information for the event
+ pre-registered type information for the event, used in
+ combination with eventPath
properties:
id:
description: The UUID of the FireFly interface
@@ -6489,7 +6494,7 @@ paths:
event:
description: The definition of the event, either provided
in-line when creating the listener, or extracted from
- the referenced FFI
+ the referenced FFI when supplied
properties:
description:
description: A description of the smart contract event
@@ -6531,7 +6536,8 @@ paths:
type: object
interface:
description: A reference to an existing FFI, containing
- pre-registered type information for the event
+ pre-registered type information for the event, used in
+ combination with eventPath
properties:
id:
description: The UUID of the FireFly interface
@@ -6683,7 +6689,7 @@ paths:
event:
description: The definition of the event, either provided
in-line when creating the listener, or extracted from the
- referenced FFI
+ referenced FFI when supplied
properties:
description:
description: A description of the smart contract event
@@ -6728,7 +6734,8 @@ paths:
type: string
interface:
description: A reference to an existing FFI, containing pre-registered
- type information for the event
+ type information for the event, used in combination with
+ eventPath
properties:
id:
description: The UUID of the FireFly interface
@@ -14132,7 +14139,7 @@ paths:
event:
description: The definition of the event, either provided
in-line when creating the listener, or extracted from
- the referenced FFI
+ the referenced FFI when supplied
properties:
description:
description: A description of the smart contract event
@@ -14176,7 +14183,8 @@ paths:
type: object
interface:
description: A reference to an existing FFI, containing
- pre-registered type information for the event
+ pre-registered type information for the event, used
+ in combination with eventPath
properties:
id:
description: The UUID of the FireFly interface
@@ -14345,7 +14353,7 @@ paths:
event:
description: The definition of the event, either provided
in-line when creating the listener, or extracted from the
- referenced FFI
+ referenced FFI when supplied
properties:
description:
description: A description of the smart contract event
@@ -14385,7 +14393,8 @@ paths:
type: object
interface:
description: A reference to an existing FFI, containing pre-registered
- type information for the event
+ type information for the event, used in combination with
+ eventPath
properties:
id:
description: The UUID of the FireFly interface
@@ -14509,7 +14518,7 @@ paths:
event:
description: The definition of the event, either provided
in-line when creating the listener, or extracted from
- the referenced FFI
+ the referenced FFI when supplied
properties:
description:
description: A description of the smart contract event
@@ -14551,7 +14560,8 @@ paths:
type: object
interface:
description: A reference to an existing FFI, containing
- pre-registered type information for the event
+ pre-registered type information for the event, used in
+ combination with eventPath
properties:
id:
description: The UUID of the FireFly interface
@@ -19041,7 +19051,7 @@ paths:
event:
description: The definition of the event, either provided
in-line when creating the listener, or extracted from
- the referenced FFI
+ the referenced FFI when supplied
properties:
description:
description: A description of the smart contract event
@@ -19085,7 +19095,8 @@ paths:
type: object
interface:
description: A reference to an existing FFI, containing
- pre-registered type information for the event
+ pre-registered type information for the event, used
+ in combination with eventPath
properties:
id:
description: The UUID of the FireFly interface
@@ -19245,7 +19256,7 @@ paths:
event:
description: The definition of the event, either provided
in-line when creating the listener, or extracted from the
- referenced FFI
+ referenced FFI when supplied
properties:
description:
description: A description of the smart contract event
@@ -19290,7 +19301,8 @@ paths:
type: string
interface:
description: A reference to an existing FFI, containing pre-registered
- type information for the event
+ type information for the event, used in combination with
+ eventPath
properties:
id:
description: The UUID of the FireFly interface
@@ -19414,7 +19426,7 @@ paths:
event:
description: The definition of the event, either provided
in-line when creating the listener, or extracted from
- the referenced FFI
+ the referenced FFI when supplied
properties:
description:
description: A description of the smart contract event
@@ -19456,7 +19468,8 @@ paths:
type: object
interface:
description: A reference to an existing FFI, containing
- pre-registered type information for the event
+ pre-registered type information for the event, used in
+ combination with eventPath
properties:
id:
description: The UUID of the FireFly interface
@@ -19666,7 +19679,7 @@ paths:
event:
description: The definition of the event, either provided
in-line when creating the listener, or extracted from
- the referenced FFI
+ the referenced FFI when supplied
properties:
description:
description: A description of the smart contract event
@@ -19708,7 +19721,8 @@ paths:
type: object
interface:
description: A reference to an existing FFI, containing
- pre-registered type information for the event
+ pre-registered type information for the event, used in
+ combination with eventPath
properties:
id:
description: The UUID of the FireFly interface
@@ -19867,7 +19881,7 @@ paths:
event:
description: The definition of the event, either provided
in-line when creating the listener, or extracted from the
- referenced FFI
+ referenced FFI when supplied
properties:
description:
description: A description of the smart contract event
@@ -19912,7 +19926,8 @@ paths:
type: string
interface:
description: A reference to an existing FFI, containing pre-registered
- type information for the event
+ type information for the event, used in combination with
+ eventPath
properties:
id:
description: The UUID of the FireFly interface
@@ -29287,7 +29302,6 @@ paths:
used in FireFly, so if your application crashes/reconnects
this is the maximum number of events you would expect
to be redelivered after it restarts
- maximum: 65535
minimum: 0
type: integer
reply:
@@ -29572,7 +29586,6 @@ paths:
At least once delivery semantics are used in FireFly, so if
your application crashes/reconnects this is the maximum number
of events you would expect to be redelivered after it restarts
- maximum: 65535
minimum: 0
type: integer
reply:
@@ -29846,7 +29859,6 @@ paths:
in FireFly, so if your application crashes/reconnects this
is the maximum number of events you would expect to be redelivered
after it restarts
- maximum: 65535
minimum: 0
type: integer
reply:
@@ -30128,7 +30140,6 @@ paths:
At least once delivery semantics are used in FireFly, so if
your application crashes/reconnects this is the maximum number
of events you would expect to be redelivered after it restarts
- maximum: 65535
minimum: 0
type: integer
reply:
@@ -30402,7 +30413,6 @@ paths:
in FireFly, so if your application crashes/reconnects this
is the maximum number of events you would expect to be redelivered
after it restarts
- maximum: 65535
minimum: 0
type: integer
reply:
@@ -30750,7 +30760,6 @@ paths:
in FireFly, so if your application crashes/reconnects this
is the maximum number of events you would expect to be redelivered
after it restarts
- maximum: 65535
minimum: 0
type: integer
reply:
@@ -38574,7 +38583,6 @@ paths:
used in FireFly, so if your application crashes/reconnects
this is the maximum number of events you would expect
to be redelivered after it restarts
- maximum: 65535
minimum: 0
type: integer
reply:
@@ -38852,7 +38860,6 @@ paths:
At least once delivery semantics are used in FireFly, so if
your application crashes/reconnects this is the maximum number
of events you would expect to be redelivered after it restarts
- maximum: 65535
minimum: 0
type: integer
reply:
@@ -39126,7 +39133,6 @@ paths:
in FireFly, so if your application crashes/reconnects this
is the maximum number of events you would expect to be redelivered
after it restarts
- maximum: 65535
minimum: 0
type: integer
reply:
@@ -39401,7 +39407,6 @@ paths:
At least once delivery semantics are used in FireFly, so if
your application crashes/reconnects this is the maximum number
of events you would expect to be redelivered after it restarts
- maximum: 65535
minimum: 0
type: integer
reply:
@@ -39675,7 +39680,6 @@ paths:
in FireFly, so if your application crashes/reconnects this
is the maximum number of events you would expect to be redelivered
after it restarts
- maximum: 65535
minimum: 0
type: integer
reply:
@@ -40009,7 +40013,6 @@ paths:
in FireFly, so if your application crashes/reconnects this
is the maximum number of events you would expect to be redelivered
after it restarts
- maximum: 65535
minimum: 0
type: integer
reply:
diff --git a/doc-site/docs/troubleshooting/index.md b/doc-site/docs/troubleshooting/index.md
new file mode 100644
index 0000000000..7b7722d95d
--- /dev/null
+++ b/doc-site/docs/troubleshooting/index.md
@@ -0,0 +1,5 @@
+---
+title: Troubleshooting
+---
+
+This section includes troubleshooting tips for identifying issues with a running FireFly node, and for gathering useful data before opening an issue.
diff --git a/doc-site/docs/troubleshooting/undelivered_messages.md b/doc-site/docs/troubleshooting/undelivered_messages.md
new file mode 100644
index 0000000000..3abfe1a71a
--- /dev/null
+++ b/doc-site/docs/troubleshooting/undelivered_messages.md
@@ -0,0 +1,95 @@
+---
+title: Undelivered messages
+---
+
+When using FireFly in multiparty mode to deliver broadcast or private messages, one potential problem is that of
+undelivered messages. In general FireFly's message delivery service should be extremely reliable, but understanding
+when something has gone wrong (and how to recover) can be important for maintaining system health.
+
+## Background
+
+This guide assumes some familiarity with how
+[multiparty event sequencing](../architecture/multiparty_event_sequencing.md) works.
+In general, FireFly messages come in three varieties:
+
+
+
+1. **Unpinned private messages:** private messages delivered directly via data exchange
+2. **Pinned private messages:** private messages delivered via data exchange, with a hash of the message recorded on the blockchain ledger
+3. **Pinned broadcast messages:** messages stored in IPFS, with a hash and reference to the message shared
+
+All messages are batched for efficiency, but in cases of low throughput, you may frequently see batches
+containing exactly one message.
+
+"Pinned" messages are those that use the blockchain ledger for reliable timestamping and ordering. These messages have
+two pieces which must be received before the message can be processed: the **batch** is the actual contents of
+the message(s), and the **pin** is the lightweight blockchain transaction that records the existence and ordering of
+that batch. We frequently refer to this combination as a **batch-pin**.
+
+> Note: there is a fourth type of message denoted with the type "definition", used for things such as identitity claims
+> and advertisement of contract APIs. For most troubleshooting purposes these can be treated the same as pinned
+> broadcast messages, as they follow the same pattern (with only a few additional processings steps inside FireFly).
+
+## Symptoms
+
+When some part of the multiparty messaging infrastructure requires troubleshooting, common symptoms include:
+
+- a message was sent, but is not present on some other node where it should have been received
+- a message is stuck indefinitely in "sent" or "pending" state
+
+## Troubleshooting steps
+
+When troubleshooting one of the symptoms above, the main goal is to identify the specific piece of the infrastructure that is
+experiencing an issue. This can lead you to diagnose specific issues such as misconfiguration, network problems, database
+integrity problems, or potential code bugs.
+
+In all cases, the **batch ID** is the most critical piece of data for determining the nature of the issue. You can usually
+retrieve the batch for a particular message by querying `/messages/` and looking for the `batch` field in the returned
+response. In rare cases, if this is not populated, you can also retrieve the message transaction via `/messages//transaction`,
+and then you can use the transaction ID to query `/batches?tx.id=`.
+
+The batch ID will be the same on all nodes involved in the messaging flow. Therefore, the following two steps can be
+easily performed to check for the existence of the expected items:
+
+- query `/batches/` on each node that should have the message
+- query `/pins?batch=` on each node that should have the message (for pinned messages only)
+
+Then choose one of these scenarios to focus in on an area of interest:
+
+#### 1) Is the batch missing on a node that should have received it?
+
+For private messages, this indicates a potential problem with **data exchange**. Check the sending node to see if the FireFly
+operations succeeded when sending the batch via data exchange, and check the data exchange logs for any issues processing it
+(the FireFly operation ID can be used to trace the operation through data exchange as well).
+If an operation failed on the sending node, you may need to retry it with `/operations//retry`.
+
+For broadcast messages, this indicates a potential problem with **IPFS**. Check the sending node to see if the FireFly
+operations succeeded when uploading the batch to IPFS, and the receiving node to see if the operations succeeded when
+downloading the batch from IPFS. If an operation failed, you may need to retry it with `/operations//retry`.
+
+#### 2) Is the batch present, but the pin is missing?
+
+This indicates a potential problem with the **blockchain connector**. Check if the underlying blockchain node is
+healthy and mining blocks. Check the sending FireFly node to see if the operation succeeded when pinning the batch via the
+blockchain. Check the blockchain connector logs (such as evmconnect or fabconnect) to see if it is
+successfully processing events from the blockchain, or if it is encountering any errors before forwarding those events
+on to FireFly.
+
+#### 3) Are the batch and pin both present, but the messages from the batch are still stuck in "sent" or "pending"?
+
+Check the pin details to see if it contains a field `"dispatched": true`. If this field is false or missing, it means
+that the pin was received but couldn't be matched successfully with the off-chain batch contents. Check the FireFly
+logs and search for the batch ID - likely this issue is in FireFly and it will have logged some problem while
+aggregating the batch-pin. In some cases, the FireFly logs may indicate that the pin could not be dispatched because
+it was "stuck" behind another pin on the same context - so you may need to follow the trail to a batch-pin for a
+different batch and determine why that earlier one was not processed (by starting over on this rubric
+and troubleshooting that batch).
+
+## Opening an issue
+
+It's possible that the above steps may lead to an obvious solution (such as recovering a crashed service or retrying a
+failed operation). If they do not, you can open an issue. The more detail you can include from the troubleshooting above
+(including the type of message, the nodes involved, and the details on the batch and pin found when examining each node),
+the more likely it is that someone can help to suggest additional troubleshooting. Full logs from FireFly, and (as
+deemed relevant from the troubleshooting above) full logs from the data exchange or blockchain connector runtimes, will
+also make it easier to offer additional insight.
diff --git a/doc-site/docs/tutorials/broadcast_data.md b/doc-site/docs/tutorials/broadcast_data.md
index 5ea6d7aed1..6f367a427f 100644
--- a/doc-site/docs/tutorials/broadcast_data.md
+++ b/doc-site/docs/tutorials/broadcast_data.md
@@ -20,7 +20,7 @@ title: Broadcast data
## Additional info
- Key Concepts: [Broadcast / shared data](../overview/multiparty/broadcast.md)
-- Swagger Reference: POST /api/v1/namespaces/{ns}/messages/broadcast
+- Swagger Reference: POST /api/v1/namespaces/{ns}/messages/broadcast
## Example 1: Inline string data
diff --git a/doc-site/docs/tutorials/chains/avalanche.md b/doc-site/docs/tutorials/chains/avalanche.md
index 01f0f10cf0..8255dc6ba6 100644
--- a/doc-site/docs/tutorials/chains/avalanche.md
+++ b/doc-site/docs/tutorials/chains/avalanche.md
@@ -1,5 +1,5 @@
---
-title: Aavalanche
+title: Avalanche
---
Starting with FireFly v1.1, it's easy to connect to public Ethereum chains. This guide will walk you through the steps to create a local FireFly development environment and connect it to the Avalanche C-Chain Fuji testnet.
diff --git a/doc-site/docs/tutorials/create_custom_identity.md b/doc-site/docs/tutorials/create_custom_identity.md
index 6524ef93bb..a8faf453f4 100644
--- a/doc-site/docs/tutorials/create_custom_identity.md
+++ b/doc-site/docs/tutorials/create_custom_identity.md
@@ -11,7 +11,7 @@ Out of the box, a FireFly Supernode contains both an `org` and a `node` identity
## Additional info
- Reference: [Identities](../reference/identities.md)
-- Swagger: POST /api/v1/identities
+- Swagger: POST /api/v1/identities
## Previous steps: Start your environment
diff --git a/doc-site/docs/tutorials/custom_contracts/index.md b/doc-site/docs/tutorials/custom_contracts/index.md
index 70a4467cd0..90cb9d5c21 100644
--- a/doc-site/docs/tutorials/custom_contracts/index.md
+++ b/doc-site/docs/tutorials/custom_contracts/index.md
@@ -49,8 +49,6 @@ Like the rest of FireFly, custom onchain logic support are implemented with an a
- The transaction itself happens asynchronously from the HTTP request that initiated it
- Blockchain events emitted by the custom onchain logic (Ethereum smart contracts, Fabric chaincodes, Corda flows, etc.) will be stored in FireFly's database if FireFly has a **Event Listener** set up for that specific type of event. FireFly will also emit an event of type `blockchain_event_received` when this happens.
-
-

diff --git a/doc-site/docs/tutorials/define_datatype.md b/doc-site/docs/tutorials/define_datatype.md
index fd24901e77..f241c3d2b0 100644
--- a/doc-site/docs/tutorials/define_datatype.md
+++ b/doc-site/docs/tutorials/define_datatype.md
@@ -20,7 +20,7 @@ of datatypes, as is used to broadcast the data itself.
## Additional info
- Key Concepts: [Broadcast / shared data](../overview/multiparty/broadcast.md)
-- Swagger: POST /api/v1/namespaces/{ns}/datatypes
+- Swagger: POST /api/v1/namespaces/{ns}/datatypes
### Example 1: Broadcast new datatype
diff --git a/doc-site/docs/tutorials/private_send.md b/doc-site/docs/tutorials/private_send.md
index 1d40c1bf0f..bb59b5997c 100644
--- a/doc-site/docs/tutorials/private_send.md
+++ b/doc-site/docs/tutorials/private_send.md
@@ -37,7 +37,7 @@ title: Privately send data
## Additional info
- Key Concepts: [Private data exchange](../overview/multiparty/data_exchange.md)
-- Swagger: POST /api/v1/namespaces/{ns}/messages/private
+- Swagger: POST /api/v1/namespaces/{ns}/messages/private
## Example 1: Pinned private send of in-line string data
diff --git a/doc-site/docs/tutorials/query_messages.md b/doc-site/docs/tutorials/query_messages.md
index a221ddd466..5785b992ac 100644
--- a/doc-site/docs/tutorials/query_messages.md
+++ b/doc-site/docs/tutorials/query_messages.md
@@ -17,7 +17,7 @@ This builds on the APIs to query and filter messages, described below
## Additional info
- Reference: [API Query Syntax](../reference/api_query_syntax.md)
-- Swagger: GET /api/v1/namespaces/{ns}/messages
+- Swagger: GET /api/v1/namespaces/{ns}/messages
### Example 1: Query confirmed messages
diff --git a/ffconfig/main.go b/ffconfig/main.go
index 37ea351a66..93c31716bc 100644
--- a/ffconfig/main.go
+++ b/ffconfig/main.go
@@ -17,6 +17,7 @@
package main
import (
+ "errors"
"fmt"
"os"
@@ -29,7 +30,7 @@ var rootCmd = &cobra.Command{
Short: "FireFly configuration tool",
Long: "Tool for managing and migrating config files for Hyperledger FireFly",
RunE: func(cmd *cobra.Command, args []string) error {
- return fmt.Errorf("a command is required")
+ return errors.New("a command is required")
},
}
diff --git a/go.mod b/go.mod
index d9ed32faa2..e3e0e6c4a1 100644
--- a/go.mod
+++ b/go.mod
@@ -17,8 +17,8 @@ require (
github.com/golang-migrate/migrate/v4 v4.17.0
github.com/gorilla/mux v1.8.1
github.com/gorilla/websocket v1.5.1
- github.com/hyperledger/firefly-common v1.4.11
- github.com/hyperledger/firefly-signer v1.1.17
+ github.com/hyperledger/firefly-common v1.4.15
+ github.com/hyperledger/firefly-signer v1.1.20
github.com/jarcoal/httpmock v1.2.0
github.com/lib/pq v1.10.9
github.com/mattn/go-sqlite3 v1.14.19
@@ -30,8 +30,8 @@ require (
github.com/spf13/viper v1.18.2
github.com/stretchr/testify v1.8.4
gitlab.com/hfuss/mux-prometheus v0.0.5
- golang.org/x/net v0.20.0
- golang.org/x/text v0.14.0
+ golang.org/x/net v0.33.0
+ golang.org/x/text v0.21.0
gopkg.in/yaml.v2 v2.4.0
)
@@ -72,7 +72,7 @@ require (
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.45.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
- github.com/rs/cors v1.10.1 // indirect
+ github.com/rs/cors v1.11.1 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
@@ -85,12 +85,12 @@ require (
github.com/x-cray/logrus-prefixed-formatter v0.5.2 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
- golang.org/x/crypto v0.18.0 // indirect
+ golang.org/x/crypto v0.31.0 // indirect
golang.org/x/exp v0.0.0-20240110193028-0dcbfd608b1e // indirect
- golang.org/x/sys v0.16.0 // indirect
- golang.org/x/term v0.16.0 // indirect
+ golang.org/x/sys v0.28.0 // indirect
+ golang.org/x/term v0.27.0 // indirect
golang.org/x/time v0.5.0 // indirect
- google.golang.org/protobuf v1.32.0 // indirect
+ google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
diff --git a/go.sum b/go.sum
index ab3abce00b..52db960a07 100644
--- a/go.sum
+++ b/go.sum
@@ -77,10 +77,10 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
-github.com/hyperledger/firefly-common v1.4.11 h1:WKv2hQuNpS7yP51THxzpzrqU3jkln23C9vq5iminzBk=
-github.com/hyperledger/firefly-common v1.4.11/go.mod h1:E7w/RxNtVnX52WXLQW9f2xVAgZnW70voZeE9sZrx/q0=
-github.com/hyperledger/firefly-signer v1.1.17 h1:JV38nNeCS/K31kPDk5mwnoqw6SoulcYF+12JW8a3/Mw=
-github.com/hyperledger/firefly-signer v1.1.17/go.mod h1:HDaDdht94JypRTunRGrcPL5Pvxfh4yigjatTrie5JUI=
+github.com/hyperledger/firefly-common v1.4.15 h1:dp4Mo2JQRPMbL7hoMw8T/ktvIUgematOLkXIppQtBp0=
+github.com/hyperledger/firefly-common v1.4.15/go.mod h1:bA7tAJxcpfQMrHN3/YycTSpyk4g2WlnDlpHx8WOUtAY=
+github.com/hyperledger/firefly-signer v1.1.20 h1:U/oGj+QuHdFp4NVZyYOzt3RW51m9nsdYQAGGeChG7g0=
+github.com/hyperledger/firefly-signer v1.1.20/go.mod h1:4S8Ki1f1d8U+Ujojea/a3mkXnJ5Fuz+JBfrf9HBdyO0=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY=
@@ -163,8 +163,8 @@ github.com/qeesung/image2ascii v1.0.1 h1:Fe5zTnX/v/qNC3OC4P/cfASOXS501Xyw2UUcgrL
github.com/qeesung/image2ascii v1.0.1/go.mod h1:kZKhyX0h2g/YXa/zdJR3JnLnJ8avHjZ3LrvEKSYyAyU=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
-github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo=
-github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
+github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
+github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
@@ -218,25 +218,27 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
-golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
-golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
+golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
+golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20240110193028-0dcbfd608b1e h1:723BNChdd0c2Wk6WOE320qGBiPtYx0F0Bbm1kriShfE=
golang.org/x/exp v0.0.0-20240110193028-0dcbfd608b1e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
-golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
-golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
-golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
+golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
+golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
+golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -249,23 +251,23 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
-golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
-golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
-golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
+golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
+golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
-golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
-golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
@@ -273,11 +275,11 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
-golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
-golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
-google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
diff --git a/go.work.sum b/go.work.sum
index e0f19a971d..863da39d56 100644
--- a/go.work.sum
+++ b/go.work.sum
@@ -21,6 +21,7 @@ cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRY
cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM=
cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I=
cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk=
+cloud.google.com/go v0.110.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y=
cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic=
cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw=
cloud.google.com/go/accessapproval v1.7.4/go.mod h1:/aTEh45LzplQgFYdQdwPMR9YdX0UlhBmvB84uAmQKUc=
@@ -91,10 +92,12 @@ cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvj
cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
cloud.google.com/go/compute v1.23.1/go.mod h1:CqB3xpmPKKt3OJpW2ndFIXnA9A4xAy/F3Xp1ixncW78=
+cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk=
cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI=
cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU=
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=
+cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck=
cloud.google.com/go/contactcenterinsights v1.11.3/go.mod h1:HHX5wrz5LHVAwfI2smIotQG9x8Qd6gYilaHcLLLmNis=
@@ -149,6 +152,7 @@ cloud.google.com/go/eventarc v1.13.3/go.mod h1:RWH10IAZIRcj1s/vClXkBgMHwh59ts7hS
cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI=
cloud.google.com/go/filestore v1.7.4/go.mod h1:S5JCxIbFjeBhWMTfIYH2Jx24J6BqjwpkkPl+nBA5DlI=
cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE=
+cloud.google.com/go/firestore v1.14.0 h1:8aLcKnMPoldYU3YHgu4t2exrKhLQkqaXAGqT0ljrFVw=
cloud.google.com/go/firestore v1.14.0/go.mod h1:96MVaHLsEhbvkBEdZgfN+AS/GIkco1LRpH9Xp9YZfzQ=
cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg=
cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08=
@@ -162,190 +166,395 @@ cloud.google.com/go/gkeconnect v0.8.4/go.mod h1:84hZz4UMlDCKl8ifVW8layK4WHlMAFeq
cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0=
cloud.google.com/go/gkehub v0.14.4/go.mod h1:Xispfu2MqnnFt8rV/2/3o73SK1snL8s9dYJ9G2oQMfc=
cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI=
+cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI=
cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8=
+cloud.google.com/go/longrunning v0.5.4 h1:w8xEcbZodnA2BbW6sVirkkoC+1gP8wS57EUUgGS0GVg=
cloud.google.com/go/longrunning v0.5.4/go.mod h1:zqNVncI0BOP8ST6XQD1+VcvuShMmq7+xFSzOL++V0dI=
+cloud.google.com/go/spanner v1.51.0 h1:l3exhhsVMKsx1E7Xd1QajYSvHmI1KZoWPW5tRxIIdvQ=
cloud.google.com/go/spanner v1.51.0/go.mod h1:c5KNo5LQ1X5tJwma9rSQZsXNBDNvj4/n8BVc3LNahq0=
+cloud.google.com/go/storage v1.35.1 h1:B59ahL//eDfx2IIKFBeT5Atm9wnNmj3+8xG/W4WB//w=
cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8=
+github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs=
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4=
+github.com/99designs/keyring v1.2.1 h1:tYLp1ULvO7i3fI5vE21ReQuj99QFSs7lGm0xWyJo87o=
github.com/99designs/keyring v1.2.1/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0 h1:rTnT/Jrcm+figWlYz4Ixzt0SJVR2cMC8lvZcimipiEY=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0/go.mod h1:ON4tFdPTwRcgWEaVDrN3584Ef+b7GgSJaXxe5fW9t4M=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2 h1:+5VZ72z0Qan5Bog5C+ZkgSqUbeVUd9wgtHOrIKuc5b8=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
+github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 h1:u/LLAOFgsMv7HmNL4Qufg58y+qElGOt5qv0z1mURkRY=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0/go.mod h1:2e8rMJtl2+2j+HXbTBwnyGpm5Nou7KhvSfxOq8JpTag=
+github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/Azure/go-autorest/autorest/adal v0.9.16 h1:P8An8Z9rH1ldbOLdFpxYorgOt2sywL9V24dAwWHPuGc=
github.com/Azure/go-autorest/autorest/adal v0.9.16/go.mod h1:tGMin8I49Yij6AQ+rvV+Xa/zwxYQB5hmsd6DkfAx2+A=
+github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
+github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg=
github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
+github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+github.com/ClickHouse/clickhouse-go v1.4.3 h1:iAFMa2UrQdR5bHJ2/yaSLffZkxpcOYQMCUuKeNXGdqc=
github.com/ClickHouse/clickhouse-go v1.4.3/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
+github.com/alecthomas/kingpin/v2 v2.3.2 h1:H0aULhgmSzN8xQ3nX1uxtdlTHYoPLu5AhHxWrKI6ocU=
github.com/alecthomas/kingpin/v2 v2.3.2/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE=
+github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
+github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
+github.com/apache/arrow/go/v10 v10.0.1 h1:n9dERvixoC/1JjDmBcs9FPaEryoANa2sCgVFo6ez9cI=
github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0=
+github.com/apache/thrift v0.16.0 h1:qEy6UW60iVOlUy+b9ZR0d5WzUWYGOo4HfopoyBaNmoY=
github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU=
+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 h1:G1bPvciwNyF7IUmKXNt9Ak3m6u9DE1rF+RmtIkBpVdA=
+github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA=
github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
+github.com/aws/aws-sdk-go v1.49.6 h1:yNldzF5kzLBRvKlKz1S0bkvc2+04R1kt13KfBWQBfFA=
github.com/aws/aws-sdk-go v1.49.6/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
+github.com/aws/aws-sdk-go-v2 v1.16.16 h1:M1fj4FE2lB4NzRb9Y0xdWsn2P0+2UHVxwKyOa4YJNjk=
github.com/aws/aws-sdk-go-v2 v1.16.16/go.mod h1:SwiyXi/1zTUZ6KIAmLK5V5ll8SiURNUYOqTerZPaF9k=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.8 h1:tcFliCWne+zOuUfKNRn8JdFBuWPDuISDH08wD2ULkhk=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.8/go.mod h1:JTnlBSot91steJeti4ryyu/tLd4Sk84O5W22L7O2EQU=
+github.com/aws/aws-sdk-go-v2/credentials v1.12.20 h1:9+ZhlDY7N9dPnUmf7CDfW9In4sW5Ff3bh7oy4DzS1IE=
github.com/aws/aws-sdk-go-v2/credentials v1.12.20/go.mod h1:UKY5HyIux08bbNA7Blv4PcXQ8cTkGh7ghHMFklaviR4=
+github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.33 h1:fAoVmNGhir6BR+RU0/EI+6+D7abM+MCwWf8v4ip5jNI=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.33/go.mod h1:84XgODVR8uRhmOnUkKGUZKqIMxmjmLOR8Uyp7G/TPwc=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.23 h1:s4g/wnzMf+qepSNgTvaQQHNxyMLKSawNhKCPNy++2xY=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.23/go.mod h1:2DFxAQ9pfIRy0imBCJv+vZ2X6RKxves6fbnEuSry6b4=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.17 h1:/K482T5A3623WJgWT8w1yRAFK4RzGzEl7y39yhtn9eA=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.17/go.mod h1:pRwaTYCJemADaqCbUAxltMoHKata7hmB5PjEXeu0kfg=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.14 h1:ZSIPAkAsCCjYrhqfw2+lNzWDzxzHXEckFkTePL5RSWQ=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.14/go.mod h1:AyGgqiKv9ECM6IZeNQtdT8NnMvUb3/2wokeq2Fgryto=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.9 h1:Lh1AShsuIJTwMkoxVCAYPJgNG5H+eN6SmoUn8nOZ5wE=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.9/go.mod h1:a9j48l6yL5XINLHLcOKInjdvknN+vWqPBxqeIDw7ktw=
+github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.18 h1:BBYoNQt2kUZUUK4bIPsKrCcjVPUMNsgQpNAwhznK/zo=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.18/go.mod h1:NS55eQ4YixUJPTC+INxi2/jCqe1y2Uw3rnh9wEOVJxY=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17 h1:Jrd/oMh0PKQc6+BowB+pLEwLIgaQF29eYbe7E1Av9Ug=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17/go.mod h1:4nYOrY41Lrbk2170/BGkcJKBhws9Pfn8MG3aGqjjeFI=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.17 h1:HfVVR1vItaG6le+Bpw6P4midjBDMKnjMyZnw9MXYUcE=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.17/go.mod h1:YqMdV+gEKCQ59NrB7rzrJdALeBIsYiVi8Inj3+KcqHI=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.27.11 h1:3/gm/JTX9bX8CpzTgIlrtYpB3EVBDxyg/GY/QdcIEZw=
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.11/go.mod h1:fmgDANqTUCxciViKl9hb/zD5LFbvPINFRgWhDbR+vZo=
+github.com/aws/smithy-go v1.13.3 h1:l7LYxGuzK6/K+NzJ2mC+VvLUbae0sL3bXU//04MkmnA=
github.com/aws/smithy-go v1.13.3/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
+github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U=
github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
+github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo=
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
+github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g=
github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
+github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 h1:F1EaeKL/ta07PY/k9Os/UFtwERei2/XzGemhpGnBKNg=
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
+github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk=
github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
+github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY=
github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cockroachdb/cockroach-go/v2 v2.1.1 h1:3XzfSMuUT0wBe1a3o5C0eOTcArhmmFAg2Jzh/7hhKqo=
github.com/cockroachdb/cockroach-go/v2 v2.1.1/go.mod h1:7NtUnP6eK+l6k483WSYNrq3Kb23bWV10IRV1TyeSpwM=
+github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04=
+github.com/coreos/go-etcd v2.0.0+incompatible h1:bXhRBIXoTm9BYHS3gE0TtQuyNZyeEMux2sDi4oo5YOo=
+github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
+github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
+github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/cucumber/gherkin-go/v19 v19.0.3 h1:mMSKu1077ffLbTJULUfM5HPokgeBcIGboyeNUof1MdE=
github.com/cucumber/gherkin-go/v19 v19.0.3/go.mod h1:jY/NP6jUtRSArQQJ5h1FXOUgk5fZK24qtE7vKi776Vw=
+github.com/cucumber/godog v0.12.6 h1:3IToXviU45G7FgijwTk/LdB4iojn8zUFDfQLj4MMiHc=
github.com/cucumber/godog v0.12.6/go.mod h1:Y02TTpimPXDb70PnG6M3zpODXm1+bjCsuZzcW76xAww=
+github.com/cucumber/messages-go/v16 v16.0.1 h1:fvkpwsLgnIm0qugftrw2YwNlio+ABe2Iu94Ap8GMYIY=
github.com/cucumber/messages-go/v16 v16.0.1/go.mod h1:EJcyR5Mm5ZuDsKJnT2N9KRnBK30BGjtYotDKpwQ0v6g=
+github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369 h1:XNT/Zf5l++1Pyg08/HV04ppB0gKxAqtZQBRYiYrUuYk=
github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
+github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0=
github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0=
+github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
+github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM=
github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU=
+github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 h1:aaQcKT9WumO6JEJcRyTqFVq4XUZiUcKR2/GI31TOcz8=
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
+github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM=
github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g=
+github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
+github.com/form3tech-oss/jwt-go v3.2.5+incompatible h1:/l4kBbb4/vGSsdtB5nUe8L7B9mImVMaBPw9L/0TBHU8=
github.com/form3tech-oss/jwt-go v3.2.5+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
+github.com/fsouza/fake-gcs-server v1.17.0 h1:OeH75kBZcZa3ZE+zz/mFdJ2btt9FgqfjI7gIh9+5fvk=
github.com/fsouza/fake-gcs-server v1.17.0/go.mod h1:D1rTE4YCyHFNa99oyJJ5HyclvN/0uQR+pM/VdlL83bw=
+github.com/gabriel-vasile/mimetype v1.4.1 h1:TRWk7se+TOjCYgRth7+1/OYLNiRNIotknkFtf/dnN7Q=
github.com/gabriel-vasile/mimetype v1.4.1/go.mod h1:05Vi0w3Y9c/lNvJOdmIwvrrAhX3rYhfQQCaf9VJcv7M=
+github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
+github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
+github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gobuffalo/here v0.6.0 h1:hYrd0a6gDmWxBM4TnrGw8mQg24iSVoIkHEk7FodQcBI=
github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM=
+github.com/gobuffalo/logger v1.0.0 h1:xw9Ko9EcC5iAFprrjJ6oZco9UpzS5MQ4jAwghsLHdy4=
+github.com/gobuffalo/packr/v2 v2.5.1 h1:TFOeY2VoGamPjQLiNDT3mn//ytzk236VMO2j7iHxJR4=
+github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/gocql/gocql v0.0.0-20210515062232-b7ef815b4556 h1:N/MD/sr6o61X+iZBAT2qEUF023s4KbA8RWfKzl0L6MQ=
github.com/gocql/gocql v0.0.0-20210515062232-b7ef815b4556/go.mod h1:DL0ekTmBSTdlNF25Orwt/JMzqIq3EJ4MVa/J/uK64OY=
+github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0=
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
+github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
+github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
+github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
+github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
+github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo=
github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/flatbuffers v2.0.8+incompatible h1:ivUb1cGomAB101ZM1T0nOiWz9pSrTMoa9+EiY7igmkM=
github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
+github.com/google/go-github/v39 v39.2.0 h1:rNNM311XtPOz5rDdsJXAp2o8F67X9FnROXTvto3aSnQ=
github.com/google/go-github/v39 v39.2.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE=
+github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
+github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
+github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
+github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
+github.com/googleapis/google-cloud-go-testing v0.0.0-20210719221736-1c9a4c676720 h1:zC34cGQu69FG7qzJ3WiKW244WfhDC3xxYMeNOX2gtUQ=
github.com/googleapis/google-cloud-go-testing v0.0.0-20210719221736-1c9a4c676720/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
+github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg=
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
+github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU=
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0=
+github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
+github.com/hashicorp/consul/api v1.25.1 h1:CqrdhYzc8XZuPnhIYZWH45toM0LB9ZeYr/gvpLVI3PE=
github.com/hashicorp/consul/api v1.25.1/go.mod h1:iiLVwR/htV7mas/sy0O+XSuEnrdBUUydemjxcUrAt4g=
+github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
+github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
+github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-memdb v1.3.3 h1:oGfEWrFuxtIUF3W2q/Jzt6G85TrMk9ey6XfYLvVe1Wo=
github.com/hashicorp/go-memdb v1.3.3/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg=
+github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
+github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY=
github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=
-github.com/hyperledger/firefly-common v1.4.11 h1:WKv2hQuNpS7yP51THxzpzrqU3jkln23C9vq5iminzBk=
+github.com/hyperledger/firefly-signer v1.1.20 h1:U/oGj+QuHdFp4NVZyYOzt3RW51m9nsdYQAGGeChG7g0=
+github.com/hyperledger/firefly-signer v1.1.20/go.mod h1:4S8Ki1f1d8U+Ujojea/a3mkXnJ5Fuz+JBfrf9HBdyO0=
+github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
+github.com/jackc/pgconn v1.14.0 h1:vrbA9Ud87g6JdFWkHTJXppVce58qPIdP7N8y0Ml/A7Q=
github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E=
+github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa h1:s+4MhCQ6YrzisK6hFJUX53drDT4UsSW3DEhKn0ifuHw=
github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds=
+github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
+github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
+github.com/jackc/pgproto3/v2 v2.3.2 h1:7eY55bdBeCz1F2fTzSz69QC+pG46jYq9/jtSPiJ5nn0=
github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
+github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw=
github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
+github.com/jackc/pgx/v4 v4.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0=
github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE=
+github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU=
github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8=
+github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
+github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/k0kubun/pp v2.3.0+incompatible h1:EKhKbi34VQDWJtq+zpsKSEhkHHs9w2P8Izbq8IhLVSo=
github.com/k0kubun/pp v2.3.0+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg=
+github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
+github.com/karrick/godirwalk v1.10.12 h1:BqUm+LuJcXjGv1d2mj3gBiQyrQ57a0rYoAmhvJQ7RDU=
+github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
+github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46 h1:veS9QfglfvqAw2e+eeNT/SbGySq8ajECXJ9e4fPoLhY=
+github.com/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4=
github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE=
+github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
+github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
+github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
+github.com/ktrysmt/go-bitbucket v0.6.4 h1:C8dUGp0qkwncKtAnozHCbbqhptefzEd1I0sfnuy9rYQ=
github.com/ktrysmt/go-bitbucket v0.6.4/go.mod h1:9u0v3hsd2rqCHRIpbir1oP7F58uo5dq19sBYvuMoyQ4=
+github.com/markbates/pkger v0.15.1 h1:3MPelV53RnGSW07izx5xGxl4e/sdRD6zqseIk0rMASY=
github.com/markbates/pkger v0.15.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/microsoft/go-mssqldb v1.0.0 h1:k2p2uuG8T5T/7Hp7/e3vMGTnnR0sU4h8d1CcC71iLHU=
github.com/microsoft/go-mssqldb v1.0.0/go.mod h1:+4wZTUnz/SV6nffv+RRRB/ss8jPng5Sho2SmM1l2ts4=
+github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs=
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY=
+github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI=
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE=
+github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs=
github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns=
+github.com/mutecomm/go-sqlcipher/v4 v4.4.0 h1:sV1tWCWGAVlPhNGT95Q+z/txFxuhAYWwHD1afF5bMZg=
github.com/mutecomm/go-sqlcipher/v4 v4.4.0/go.mod h1:PyN04SaWalavxRGH9E8ZftG6Ju7rsPrGmQRjrEaVpiY=
+github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8 h1:P48LjvUQpTReR3TQRbxSeSBsMXzfK0uol7eRcr7VBYQ=
github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA=
+github.com/nats-io/nats.go v1.31.0 h1:/WFBHEc/dOKBF6qf1TZhrdEfTmOZ5JzdJ+Y3m6Y/p7E=
github.com/nats-io/nats.go v1.31.0/go.mod h1:di3Bm5MLsoB4Bx61CBTsxuarI36WbhAwOm8QrW39+i8=
+github.com/nats-io/nkeys v0.4.6 h1:IzVe95ru2CT6ta874rt9saQRkWfe2nFj1NtvYSLqMzY=
github.com/nats-io/nkeys v0.4.6/go.mod h1:4DxZNzenSVd1cYQoAa8948QY3QDjrHfcfVADymtkpts=
+github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
+github.com/neo4j/neo4j-go-driver v1.8.1-0.20200803113522-b626aa943eba h1:fhFP5RliM2HW/8XdcO5QngSfFli9GcRIpMXvypTQt6E=
github.com/neo4j/neo4j-go-driver v1.8.1-0.20200803113522-b626aa943eba/go.mod h1:ncO5VaFWh0Nrt+4KT4mOZboaczBZcLuHrG+/sUeP8gI=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
+github.com/pierrec/lz4/v4 v4.1.16 h1:kQPfno+wyx6C5572ABwV+Uo3pDFzQ7yhyGchSyRda0c=
github.com/pierrec/lz4/v4 v4.1.16/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
+github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
+github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A=
+github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo=
github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk=
+github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
+github.com/rqlite/gorqlite v0.0.0-20230708021416-2acd02b70b79 h1:V7x0hCAgL8lNGezuex1RW1sh7VXXCqfw8nXZti66iFg=
github.com/rqlite/gorqlite v0.0.0-20230708021416-2acd02b70b79/go.mod h1:xF/KoXmrRyahPfo5L7Szb5cAAUl53dMWBh9cMruGEZg=
+github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
+github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
+github.com/sagikazarmark/crypt v0.17.0 h1:ZA/7pXyjkHoK4bW4mIdnCLvL8hd+Nrbiw7Dqk7D4qUk=
github.com/sagikazarmark/crypt v0.17.0/go.mod h1:SMtHTvdmsZMuY/bpZoqokSoChIrcJ/epOxZN58PbZDg=
+github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/snowflakedb/gosnowflake v1.6.19 h1:KSHXrQ5o7uso25hNIzi/RObXtnSGkFgie91X82KcvMY=
github.com/snowflakedb/gosnowflake v1.6.19/go.mod h1:FM1+PWUdwB9udFDsXdfD58NONC0m+MlOSmQRvimobSM=
+github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
+github.com/xanzy/go-gitlab v0.15.0 h1:rWtwKTgEnXyNUGrOArN7yyc3THRkpYcKXIXia9abywQ=
github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs=
+github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
+github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E=
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
+github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs=
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
+github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 h1:ESFSdwYZvkeru3RtdrYueztKhOBCSAAzS4Gf+k0tEow=
+github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
+github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
+github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
+gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b h1:7gd+rd8P3bqcn/96gOZa3F5dpJr/vEiDQYlNb/y2uNs=
gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE=
+go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k=
go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI=
+go.etcd.io/etcd/client/pkg/v3 v3.5.10 h1:kfYIdQftBnbAq8pUWFXfpuuxFSKzlmM5cSn76JByiT0=
go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U=
+go.etcd.io/etcd/client/v2 v2.305.10 h1:MrmRktzv/XF8CvtQt+P6wLUlURaNpSDJHFZhe//2QE4=
go.etcd.io/etcd/client/v2 v2.305.10/go.mod h1:m3CKZi69HzilhVqtPDcjhSGp+kA1OmbNn0qamH80xjA=
+go.etcd.io/etcd/client/v3 v3.5.10 h1:W9TXNZ+oB3MCd/8UjxHTWK5J9Nquw9fQBLJd5ne5/Ao=
go.etcd.io/etcd/client/v3 v3.5.10/go.mod h1:RVeBnDz2PUEZqTpgqwAtUd8nAPf5kjyFyND7P1VkOKc=
+go.mongodb.org/mongo-driver v1.7.5 h1:ny3p0reEpgsR2cfA5cjgwFZg3Cv/ofFh/8jbhGtz9VI=
go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng=
+go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
+go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
+golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
+golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
+golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ=
golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
+golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
+golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
+google.golang.org/api v0.153.0 h1:N1AwGhielyKFaUqH07/ZSIQR3uNPcV7NVw0vj+j4iR4=
google.golang.org/api v0.153.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY=
+google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac h1:ZL/Teoy/ZGnzyrqK/Optxxp2pmVh+fmJ97slxSRyzUg=
google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:+Rvu7ElI+aLzyDQhpHMFMMltsD6m7nqpuWDd2CwJw3k=
+google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo=
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4=
+gopkg.in/bson.v2 v2.0.0-20171018101713-d8c8987b8862 h1:l7JQszYQzJc0GspaN+sivv8wScShqfkhS3nsgID8ees=
gopkg.in/bson.v2 v2.0.0-20171018101713-d8c8987b8862/go.mod h1:VN8wuk/3Ksp8lVZ82HHf/MI1FHOBDt5bPK9VZ8DvymM=
+gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=
+gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw=
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
+lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
+modernc.org/b v1.0.0 h1:vpvqeyp17ddcQWF29Czawql4lDdABCDRbXRAS4+aF2o=
modernc.org/b v1.0.0/go.mod h1:uZWcZfRj1BpYzfN9JTerzlNUnnPsV9O2ZA8JsRcubNg=
+modernc.org/cc/v3 v3.36.3 h1:uISP3F66UlixxWEcKuIWERa4TwrZENHSL8tWxZz8bHg=
modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
+modernc.org/ccgo/v3 v3.16.9 h1:AXquSwg7GuMk11pIdw7fmO1Y/ybgazVkMhsZWCV0mHM=
modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo=
+modernc.org/db v1.0.0 h1:2c6NdCfaLnshSvY7OU09cyAY0gYXUZj4lmg5ItHyucg=
modernc.org/db v1.0.0/go.mod h1:kYD/cO29L/29RM0hXYl4i3+Q5VojL31kTUVpVJDw0s8=
+modernc.org/file v1.0.0 h1:9/PdvjVxd5+LcWUQIfapAWRGOkDLK90rloa8s/au06A=
modernc.org/file v1.0.0/go.mod h1:uqEokAEn1u6e+J45e54dsEA/pw4o7zLrA2GwyntZzjw=
+modernc.org/fileutil v1.0.0 h1:Z1AFLZwl6BO8A5NldQg/xTSjGLetp+1Ubvl4alfGx8w=
modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8=
+modernc.org/golex v1.0.0 h1:wWpDlbK8ejRfSyi0frMyhilD3JBvtcx2AdGDnU+JtsE=
modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
+modernc.org/internal v1.0.0 h1:XMDsFDcBDsibbBnHB2xzljZ+B1yrOVLEFkKL2u15Glw=
modernc.org/internal v1.0.0/go.mod h1:VUD/+JAkhCpvkUitlEOnhpVxCgsBI90oTzSCRcqQVSM=
+modernc.org/libc v1.17.1 h1:Q8/Cpi36V/QBfuQaFVeisEBs3WqoGAJprZzmf7TfEYI=
modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s=
+modernc.org/lldb v1.0.0 h1:6vjDJxQEfhlOLwl4bhpwIz00uyFK4EmSYcbwqwbynsc=
modernc.org/lldb v1.0.0/go.mod h1:jcRvJGWfCGodDZz8BPwiKMJxGJngQ/5DrRapkQnLob8=
+modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
+modernc.org/memory v1.2.1 h1:dkRh86wgmq/bJu2cAS2oqBCz/KsMZU7TUM4CibQ7eBs=
modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
+modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
+modernc.org/ql v1.0.0 h1:bIQ/trWNVjQPlinI6jdOQsi195SIturGo3mp5hsDqVU=
modernc.org/ql v1.0.0/go.mod h1:xGVyrLIatPcO2C1JvI/Co8c0sr6y91HKFNy4pt9JXEY=
+modernc.org/sortutil v1.1.0 h1:oP3U4uM+NT/qBQcbg/K2iqAX0Nx7B1b6YZtq3Gk/PjM=
modernc.org/sortutil v1.1.0/go.mod h1:ZyL98OQHJgH9IEfN71VsamvJgrtRX9Dj2gX+vH86L1k=
+modernc.org/sqlite v1.18.1 h1:ko32eKt3jf7eqIkCgPAeHMBXw3riNSLhl2f3loEF7o8=
modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4=
+modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
+modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
+modernc.org/zappy v1.0.0 h1:dPVaP+3ueIUv4guk8PuZ2wiUGcJ1WUVvIheeSSTD0yk=
modernc.org/zappy v1.0.0/go.mod h1:hHe+oGahLVII/aTTyWK/b53VDHMAGCBYYeZ9sn83HC4=
diff --git a/internal/apiserver/ffi2swagger.go b/internal/apiserver/ffi2swagger.go
index b5699b50d5..c7c3373127 100644
--- a/internal/apiserver/ffi2swagger.go
+++ b/internal/apiserver/ffi2swagger.go
@@ -81,7 +81,7 @@ func (swg *ffiSwaggerGen) Build(ctx context.Context, api *core.ContractAPI, ffi
func addFFIMethod(ctx context.Context, routes []*ffapi.Route, method *fftypes.FFIMethod, hasLocation bool) []*ffapi.Route {
description := method.Description
- if method.Details != nil && len(method.Details) > 0 {
+ if len(method.Details) > 0 {
additionalDetailsHeader := i18n.Expand(ctx, coremsgs.APISmartContractDetails)
description = fmt.Sprintf("%s\n\n%s:\n\n%s", description, additionalDetailsHeader, buildDetailsTable(ctx, method.Details))
}
@@ -117,7 +117,7 @@ func addFFIMethod(ctx context.Context, routes []*ffapi.Route, method *fftypes.FF
func addFFIEvent(ctx context.Context, routes []*ffapi.Route, event *fftypes.FFIEvent, hasLocation bool) []*ffapi.Route {
description := event.Description
- if event.Details != nil && len(event.Details) > 0 {
+ if len(event.Details) > 0 {
additionalDetailsHeader := i18n.Expand(ctx, coremsgs.APISmartContractDetails)
description = fmt.Sprintf("%s\n\n%s:\n\n%s", description, additionalDetailsHeader, buildDetailsTable(ctx, event.Details))
}
diff --git a/internal/apiserver/metrics_server.go b/internal/apiserver/metrics_server.go
index 7e80ba7c25..68de6abf5b 100644
--- a/internal/apiserver/metrics_server.go
+++ b/internal/apiserver/metrics_server.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2022 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -21,11 +21,17 @@ import (
)
const (
- MetricsEnabled = "enabled"
- MetricsPath = "path"
+ Enabled = "enabled"
+ DeprecatedMetricsPath = "path"
+ MetricsPath = "metricsPath"
)
-func initMetricsConfig(config config.Section) {
- config.AddKnownKey(MetricsEnabled, true)
+func initDeprecatedMetricsConfig(config config.Section) {
+ config.AddKnownKey(Enabled, true)
+ config.AddKnownKey(DeprecatedMetricsPath, "/metrics")
+}
+
+func initMonitoringConfig(config config.Section) {
+ config.AddKnownKey(Enabled, false)
config.AddKnownKey(MetricsPath, "/metrics")
}
diff --git a/internal/apiserver/route_get_subscription_events_filtered_test.go b/internal/apiserver/route_get_subscription_events_filtered_test.go
index fd480294dd..152e4637af 100644
--- a/internal/apiserver/route_get_subscription_events_filtered_test.go
+++ b/internal/apiserver/route_get_subscription_events_filtered_test.go
@@ -82,4 +82,4 @@ func TestGetSubscriptionEventsFilteredNoSequenceIDsProvided(t *testing.T) {
r.ServeHTTP(res, req)
assert.Equal(t, 200, res.Result().StatusCode)
-}
\ No newline at end of file
+}
diff --git a/internal/apiserver/server.go b/internal/apiserver/server.go
index ca1671a051..33b977dd22 100644
--- a/internal/apiserver/server.go
+++ b/internal/apiserver/server.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2024 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -42,10 +42,11 @@ import (
)
var (
- spiConfig = config.RootSection("spi")
- apiConfig = config.RootSection("http")
- metricsConfig = config.RootSection("metrics")
- corsConfig = config.RootSection("cors")
+ spiConfig = config.RootSection("spi")
+ apiConfig = config.RootSection("http")
+ deprecatedMetricsConfig = config.RootSection("metrics")
+ monitoringConfig = config.RootSection("monitoring")
+ corsConfig = config.RootSection("cors")
)
// Server is the external interface for the API Server
@@ -55,31 +56,35 @@ type Server interface {
type apiServer struct {
// Defaults set with config
- apiTimeout time.Duration
- apiMaxTimeout time.Duration
- metricsEnabled bool
- ffiSwaggerGen FFISwaggerGen
- apiPublicURL string
- dynamicPublicURLHeader string
- defaultNamespace string
+ apiTimeout time.Duration
+ apiMaxTimeout time.Duration
+ deprecatedMetricsEnabled bool
+ monitoringEnabled bool
+ ffiSwaggerGen FFISwaggerGen
+ apiPublicURL string
+ dynamicPublicURLHeader string
+ defaultNamespace string
}
func InitConfig() {
httpserver.InitHTTPConfig(apiConfig, 5000)
httpserver.InitHTTPConfig(spiConfig, 5001)
- httpserver.InitHTTPConfig(metricsConfig, 6000)
+ httpserver.InitHTTPConfig(deprecatedMetricsConfig, 6000)
+ httpserver.InitHTTPConfig(monitoringConfig, 6000)
httpserver.InitCORSConfig(corsConfig)
- initMetricsConfig(metricsConfig)
+ initDeprecatedMetricsConfig(deprecatedMetricsConfig)
+ initMonitoringConfig(monitoringConfig)
}
func NewAPIServer() Server {
as := &apiServer{
- apiTimeout: config.GetDuration(coreconfig.APIRequestTimeout),
- apiMaxTimeout: config.GetDuration(coreconfig.APIRequestMaxTimeout),
- dynamicPublicURLHeader: config.GetString(coreconfig.APIDynamicPublicURLHeader),
- defaultNamespace: config.GetString(coreconfig.NamespacesDefault),
- metricsEnabled: config.GetBool(coreconfig.MetricsEnabled),
- ffiSwaggerGen: &ffiSwaggerGen{},
+ apiTimeout: config.GetDuration(coreconfig.APIRequestTimeout),
+ apiMaxTimeout: config.GetDuration(coreconfig.APIRequestMaxTimeout),
+ dynamicPublicURLHeader: config.GetString(coreconfig.APIDynamicPublicURLHeader),
+ defaultNamespace: config.GetString(coreconfig.NamespacesDefault),
+ deprecatedMetricsEnabled: config.GetBool(coreconfig.DeprecatedMetricsEnabled),
+ monitoringEnabled: config.GetBool(coreconfig.MonitoringEnabled),
+ ffiSwaggerGen: &ffiSwaggerGen{},
}
as.apiPublicURL = as.getPublicURL(apiConfig, "")
return as
@@ -110,15 +115,22 @@ func (as *apiServer) Serve(ctx context.Context, mgr namespace.Manager) (err erro
} else if config.GetBool(coreconfig.LegacyAdminEnabled) {
log.L(ctx).Warnf("Your config includes an 'admin' section, which should be renamed to 'spi' - SPI server will not be enabled until this is corrected")
}
-
- if as.metricsEnabled {
- metricsHTTPServer, err := httpserver.NewHTTPServer(ctx, "metrics", as.createMetricsMuxRouter(), metricsErrChan, metricsConfig, corsConfig, &httpserver.ServerOptions{
- MaximumRequestTimeout: as.apiMaxTimeout,
- })
+ if as.deprecatedMetricsEnabled || as.monitoringEnabled {
+ var monitoringServer httpserver.HTTPServer
+ var err error
+ if as.monitoringEnabled {
+ monitoringServer, err = httpserver.NewHTTPServer(ctx, "monitoring", as.createMonitoringMuxRouter(), metricsErrChan, monitoringConfig, corsConfig, &httpserver.ServerOptions{
+ MaximumRequestTimeout: as.apiMaxTimeout,
+ })
+ } else {
+ monitoringServer, err = httpserver.NewHTTPServer(ctx, "metrics", as.createMonitoringMuxRouter(), metricsErrChan, deprecatedMetricsConfig, corsConfig, &httpserver.ServerOptions{
+ MaximumRequestTimeout: as.apiMaxTimeout,
+ })
+ }
if err != nil {
return err
}
- go metricsHTTPServer.ServeHTTP(ctx)
+ go monitoringServer.ServeHTTP(ctx)
}
return as.waitForServerStop(httpErrChan, spiErrChan, metricsErrChan)
@@ -345,7 +357,7 @@ func (as *apiServer) createMuxRouter(ctx context.Context, mgr namespace.Manager)
r := mux.NewRouter()
hf := as.handlerFactory()
- if as.metricsEnabled {
+ if as.deprecatedMetricsEnabled || as.monitoringEnabled {
r.Use(metrics.GetRestServerInstrumentation().Middleware)
}
@@ -433,7 +445,7 @@ func (as *apiServer) spiWSHandler(mgr namespace.Manager) http.HandlerFunc {
func (as *apiServer) createAdminMuxRouter(mgr namespace.Manager) *mux.Router {
r := mux.NewRouter()
- if as.metricsEnabled {
+ if as.deprecatedMetricsEnabled || as.monitoringEnabled {
r.Use(metrics.GetAdminServerInstrumentation().Middleware)
}
hf := as.handlerFactory()
@@ -468,12 +480,20 @@ func (as *apiServer) createAdminMuxRouter(mgr namespace.Manager) *mux.Router {
return r
}
-func (as *apiServer) createMetricsMuxRouter() *mux.Router {
+func (as *apiServer) createMonitoringMuxRouter() *mux.Router {
r := mux.NewRouter()
-
- r.Path(config.GetString(coreconfig.MetricsPath)).Handler(promhttp.InstrumentMetricHandler(metrics.Registry(),
+ metricsPath := config.GetString(coreconfig.DeprecatedMetricsPath)
+ if as.monitoringEnabled {
+ metricsPath = config.GetString(coreconfig.MonitoringMetricsPath)
+ }
+ r.Path(metricsPath).Handler(promhttp.InstrumentMetricHandler(metrics.Registry(),
promhttp.HandlerFor(metrics.Registry(), promhttp.HandlerOpts{})))
-
+ hf := ffapi.HandlerFactory{}
+ r.HandleFunc("/livez", hf.APIWrapper(func(res http.ResponseWriter, req *http.Request) (status int, err error) {
+ // a simple liveness check
+ return http.StatusOK, nil
+ }))
+ r.NotFoundHandler = hf.APIWrapper(as.notFoundHandler)
return r
}
diff --git a/internal/apiserver/server_test.go b/internal/apiserver/server_test.go
index 7855a033ef..444cb13e92 100644
--- a/internal/apiserver/server_test.go
+++ b/internal/apiserver/server_test.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2021 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -86,7 +86,7 @@ func TestStartStopServer(t *testing.T) {
InitConfig()
apiConfig.Set(httpserver.HTTPConfPort, 0)
spiConfig.Set(httpserver.HTTPConfPort, 0)
- metricsConfig.Set(httpserver.HTTPConfPort, 0)
+ monitoringConfig.Set(httpserver.HTTPConfPort, 0)
config.Set(coreconfig.UIPath, "test")
config.Set(coreconfig.SPIEnabled, true)
ctx, cancel := context.WithCancel(context.Background())
@@ -105,7 +105,7 @@ func TestStartLegacyAdminConfig(t *testing.T) {
InitConfig()
apiConfig.Set(httpserver.HTTPConfPort, 0)
spiConfig.Set(httpserver.HTTPConfPort, 0)
- metricsConfig.Set(httpserver.HTTPConfPort, 0)
+ monitoringConfig.Set(httpserver.HTTPConfPort, 0)
config.Set(coreconfig.UIPath, "test")
config.Set(coreconfig.LegacyAdminEnabled, true)
ctx, cancel := context.WithCancel(context.Background())
@@ -170,8 +170,8 @@ func TestStartMetricsFail(t *testing.T) {
coreconfig.Reset()
metrics.Clear()
InitConfig()
- metricsConfig.Set(httpserver.HTTPConfAddress, "...://")
- config.Set(coreconfig.MetricsEnabled, true)
+ monitoringConfig.Set(httpserver.HTTPConfAddress, "...://")
+ config.Set(coreconfig.MonitoringEnabled, true)
ctx, cancel := context.WithCancel(context.Background())
cancel() // server will immediately shut down
as := NewAPIServer()
@@ -575,3 +575,17 @@ func TestContractAPIDefaultNS(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, 200, res.StatusCode())
}
+
+func TestMonitoringServerRoutes(t *testing.T) {
+ _, _, as := newTestServer()
+ s := httptest.NewServer(as.createMonitoringMuxRouter())
+ defer s.Close()
+
+ res, err := http.Get(fmt.Sprintf("http://%s/livez", s.Listener.Addr()))
+ assert.NoError(t, err)
+ assert.Equal(t, 200, res.StatusCode)
+
+ res, err = http.Get(fmt.Sprintf("http://%s/metrics", s.Listener.Addr()))
+ assert.NoError(t, err)
+ assert.Equal(t, 200, res.StatusCode)
+}
diff --git a/internal/batch/batch_manager.go b/internal/batch/batch_manager.go
index 95dd845a4e..ee77ce3b3b 100644
--- a/internal/batch/batch_manager.go
+++ b/internal/batch/batch_manager.go
@@ -44,7 +44,11 @@ func NewBatchManager(ctx context.Context, ns string, di database.Plugin, dm data
return nil, i18n.NewError(ctx, coremsgs.MsgInitializationNilDepError, "BatchManager")
}
pCtx, cancelCtx := context.WithCancel(log.WithLogField(ctx, "role", "batchmgr"))
- readPageSize := config.GetUint(coreconfig.BatchManagerReadPageSize)
+ readPageSize := uint16(1)
+ confReadPageSize := config.GetUint64(coreconfig.BatchManagerReadPageSize)
+ if confReadPageSize > 0 && confReadPageSize <= 65535 {
+ readPageSize = uint16(confReadPageSize)
+ }
bm := &batchManager{
ctx: pCtx,
cancelCtx: cancelCtx,
@@ -54,7 +58,7 @@ func NewBatchManager(ctx context.Context, ns string, di database.Plugin, dm data
data: dm,
txHelper: txHelper,
readOffset: -1, // On restart we trawl for all ready messages
- readPageSize: uint64(readPageSize),
+ readPageSize: readPageSize,
minimumPollDelay: config.GetDuration(coreconfig.BatchManagerMinimumPollDelay),
messagePollTimeout: config.GetDuration(coreconfig.BatchManagerReadPollTimeout),
startupOffsetRetryAttempts: config.GetInt(coreconfig.OrchestratorStartupAttempts),
@@ -116,7 +120,7 @@ type batchManager struct {
inflightSequences map[int64]*batchProcessor
inflightFlushed []int64
shoulderTap chan bool
- readPageSize uint64
+ readPageSize uint16
minimumPollDelay time.Duration
messagePollTimeout time.Duration
startupOffsetRetryAttempts int
@@ -126,7 +130,7 @@ type DispatchHandler func(context.Context, *DispatchPayload) error
type DispatcherOptions struct {
BatchType core.BatchType
- BatchMaxSize uint
+ BatchMaxSize int
BatchMaxBytes int64
BatchTimeout time.Duration
DisposeTimeout time.Duration
@@ -279,11 +283,11 @@ func (bm *batchManager) readPage(lastPageFull bool) ([]*core.IDAndSequence, bool
// Read a page from the DB
var ids []*core.IDAndSequence
err := bm.retry.Do(bm.ctx, "retrieve messages", func(attempt int) (retry bool, err error) {
- fb := database.MessageQueryFactory.NewFilterLimit(bm.ctx, bm.readPageSize)
+ fb := database.MessageQueryFactory.NewFilterLimit(bm.ctx, uint64(bm.readPageSize))
ids, err = bm.database.GetMessageIDs(bm.ctx, bm.namespace, fb.And(
fb.Gt("sequence", bm.readOffset),
fb.Eq("state", core.MessageStateReady),
- ).Sort("sequence").Limit(bm.readPageSize))
+ ).Sort("sequence").Limit(uint64(bm.readPageSize)))
return true, err
})
@@ -549,6 +553,7 @@ func (bm *batchManager) maskContext(ctx context.Context, state *dispatchState, m
// Now we have the nonce, add that at the end of the hash to make it unqiue to this message
nonceBytes := make([]byte, 8)
+ //nolint:gosec
binary.BigEndian.PutUint64(nonceBytes, uint64(nonce))
hashBuilder.Write(nonceBytes)
diff --git a/internal/batch/batch_manager_test.go b/internal/batch/batch_manager_test.go
index 00987c9ddd..61e436ee9d 100644
--- a/internal/batch/batch_manager_test.go
+++ b/internal/batch/batch_manager_test.go
@@ -53,6 +53,7 @@ func newTestBatchManager(t *testing.T) (*batchManager, func()) {
cmi := &cachemocks.Manager{}
cmi.On("GetCache", mock.Anything).Return(cache.NewUmanagedCache(ctx, 100, 5*time.Minute), nil)
txHelper, _ := txcommon.NewTransactionHelper(ctx, "ns1", mdi, mdm, cmi)
+ config.Set(coreconfig.BatchManagerReadPageSize, 0) // will get min value of 1
bm, err := NewBatchManager(context.Background(), "ns1", mdi, mdm, mim, txHelper)
assert.NoError(t, err)
return bm.(*batchManager), bm.(*batchManager).cancelCtx
diff --git a/internal/batch/batch_processor.go b/internal/batch/batch_processor.go
index c4496f0ac7..7079c9d13b 100644
--- a/internal/batch/batch_processor.go
+++ b/internal/batch/batch_processor.go
@@ -228,7 +228,7 @@ func (bp *batchProcessor) addWork(newWork *batchWork) (full, overflow bool) {
bp.assemblyQueueBytes += newWork.estimateSize()
bp.assemblyQueue = newQueue
- full = len(bp.assemblyQueue) >= int(bp.conf.BatchMaxSize) || bp.assemblyQueueBytes >= bp.conf.BatchMaxBytes
+ full = len(bp.assemblyQueue) >= bp.conf.BatchMaxSize || bp.assemblyQueueBytes >= bp.conf.BatchMaxBytes
overflow = len(bp.assemblyQueue) > 1 && (batchOfOne || bp.assemblyQueueBytes > bp.conf.BatchMaxBytes)
}
@@ -633,6 +633,12 @@ func (bp *batchProcessor) dispatchBatch(payload *DispatchPayload) error {
}
}
}
+ conflictErr, conflictTestOk := err.(operations.ConflictError)
+ if conflictTestOk && conflictErr.IsConflictError() {
+ // We know that the connector has received our batch, so we shouldn't need to retry
+ payload.addMessageUpdate(payload.Messages, core.MessageStateReady, core.MessageStateSent)
+ return true, nil
+ }
} else {
if core.IsPinned(payload.Batch.TX.Type) {
payload.addMessageUpdate(payload.Messages, core.MessageStateReady, core.MessageStateSent)
diff --git a/internal/batch/batch_processor_test.go b/internal/batch/batch_processor_test.go
index fde0426605..f5704b60e0 100644
--- a/internal/batch/batch_processor_test.go
+++ b/internal/batch/batch_processor_test.go
@@ -75,6 +75,18 @@ func mockRunAsGroupPassthrough(mdi *databasemocks.Plugin) {
}
}
+type testConflictError struct {
+ err error
+}
+
+func (tce *testConflictError) Error() string {
+ return tce.err.Error()
+}
+
+func (tce *testConflictError) IsConflictError() bool {
+ return true
+}
+
func TestUnfilledBatch(t *testing.T) {
log.SetLevel("debug")
coreconfig.Reset()
@@ -129,6 +141,17 @@ func TestUnfilledBatch(t *testing.T) {
mim.AssertExpectations(t)
}
+func TestHandleDispatchConflictError(t *testing.T) {
+ cancel, _, bp := newTestBatchProcessor(t, func(c context.Context, state *DispatchPayload) error {
+ conflictErr := testConflictError{err: fmt.Errorf("pop")}
+ return &conflictErr
+ })
+ defer cancel()
+ bp.dispatchBatch(&DispatchPayload{})
+ bp.cancelCtx()
+ <-bp.done
+}
+
func TestBatchSizeOverflow(t *testing.T) {
log.SetLevel("debug")
coreconfig.Reset()
diff --git a/internal/blockchain/common/common.go b/internal/blockchain/common/common.go
index d15e0b8c4a..0393b45b74 100644
--- a/internal/blockchain/common/common.go
+++ b/internal/blockchain/common/common.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2023 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -43,6 +43,12 @@ type BlockchainCallbacks interface {
SetHandler(namespace string, handler blockchain.Callbacks)
SetOperationalHandler(namespace string, handler core.OperationCallbacks)
+ // BulkOperationUpdates is a synchronous way to update multiple operations and will return when the updates have been committed to the database or there has been an error
+ // An insertion ordering guarantee is only provided when this code is called on a single goroutine inside of the connector.
+ // It is the responsibility of the connector code to allocate that routine, and ensure that there is only one.
+ // Note: onComplete at each update level is not called, as this is a bulk operation and should be reponsibility of the caller to manage if needed.
+ BulkOperationUpdates(ctx context.Context, namespace string, updates []*core.OperationUpdate) error
+
OperationUpdate(ctx context.Context, plugin core.Named, nsOpID string, status core.OpStatus, blockchainTXID, errorMessage string, opOutput fftypes.JSONObject)
// Common logic for parsing a BatchPinOrNetworkAction event, and if not discarded to add it to the by-namespace map
PrepareBatchPinOrNetworkAction(ctx context.Context, events EventsToDispatch, subInfo *SubscriptionInfo, location *fftypes.JSONAny, event *blockchain.Event, signingKey *core.VerifierRef, params *BatchPinParams)
@@ -64,6 +70,17 @@ type callbacks struct {
opHandlers map[string]core.OperationCallbacks
}
+// BulkOperationUpdates implements BlockchainCallbacks.
+func (cb *callbacks) BulkOperationUpdates(ctx context.Context, namespace string, updates []*core.OperationUpdate) error {
+ if handler, ok := cb.opHandlers[namespace]; ok {
+ return handler.BulkOperationUpdates(ctx, updates)
+ }
+ // We don't want to error as it just means this update was not for this namespace
+ // This is unlikely to happen in practice, as the namespace is always passed in the operation handler
+ log.L(ctx).Errorf("No operation handler found for namespace '%s'", namespace)
+ return nil
+}
+
type subscriptions struct {
subs map[string]*SubscriptionInfo
}
@@ -153,13 +170,15 @@ func (cb *callbacks) SetOperationalHandler(namespace string, handler core.Operat
func (cb *callbacks) OperationUpdate(ctx context.Context, plugin core.Named, nsOpID string, status core.OpStatus, blockchainTXID, errorMessage string, opOutput fftypes.JSONObject) {
namespace, _, _ := core.ParseNamespacedOpID(ctx, nsOpID)
if handler, ok := cb.opHandlers[namespace]; ok {
- handler.OperationUpdate(&core.OperationUpdate{
- Plugin: plugin.Name(),
- NamespacedOpID: nsOpID,
- Status: status,
- BlockchainTXID: blockchainTXID,
- ErrorMessage: errorMessage,
- Output: opOutput,
+ handler.OperationUpdate(&core.OperationUpdateAsync{
+ OperationUpdate: core.OperationUpdate{
+ Plugin: plugin.Name(),
+ NamespacedOpID: nsOpID,
+ Status: status,
+ BlockchainTXID: blockchainTXID,
+ ErrorMessage: errorMessage,
+ Output: opOutput,
+ },
})
return
}
@@ -392,9 +411,17 @@ func (s *subscriptions) GetSubscription(subID string) *SubscriptionInfo {
}
// Common function for handling receipts from blockchain connectors.
-func HandleReceipt(ctx context.Context, plugin core.Named, reply *BlockchainReceiptNotification, callbacks BlockchainCallbacks) error {
+func HandleReceipt(ctx context.Context, namespace string, plugin core.Named, reply *BlockchainReceiptNotification, callbacks BlockchainCallbacks) error {
l := log.L(ctx)
+ if namespace != "" {
+ opNamespace, _, _ := core.ParseNamespacedOpID(ctx, reply.Headers.ReceiptID)
+ if opNamespace != namespace {
+ l.Debugf("Ignoring operation update from other namespace: request=%s tx=%s message=%s", reply.Headers.ReceiptID, reply.TxHash, reply.Message)
+ return nil
+ }
+ }
+
if reply.Headers.ReceiptID == "" || reply.Headers.ReplyType == "" {
return fmt.Errorf("reply cannot be processed - missing fields: %+v", reply)
}
@@ -409,7 +436,7 @@ func HandleReceipt(ctx context.Context, plugin core.Named, reply *BlockchainRece
updateType = core.OpStatusFailed
}
- // Slightly upgly conversion from ReceiptFromBlockchain -> JSONObject which the generic OperationUpdate() function requires
+ // Slightly ugly conversion from ReceiptFromBlockchain -> JSONObject which the generic OperationUpdate() function requires
var output fftypes.JSONObject
obj, err := json.Marshal(reply)
if err != nil {
diff --git a/internal/blockchain/common/common_test.go b/internal/blockchain/common/common_test.go
index 402a40339d..b59b27a4c4 100644
--- a/internal/blockchain/common/common_test.go
+++ b/internal/blockchain/common/common_test.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2022 Kaleido, Inc.
+// Copyright ยฉ 2024 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -44,7 +44,7 @@ func TestCallbackOperationUpdate(t *testing.T) {
cb.SetOperationalHandler("ns1", mcb)
mbi.On("Name").Return("utblockchain")
- mcb.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdate) bool {
+ mcb.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdateAsync) bool {
return update.NamespacedOpID == nsOpID &&
update.Status == core.OpStatusSucceeded &&
update.BlockchainTXID == "tx1" &&
@@ -342,15 +342,15 @@ func TestGoodSuccessReceipt(t *testing.T) {
cb.SetHandler("ns1", mcb)
mcb.On("OperationUpdate", "ns1", mock.Anything).Return()
- err := HandleReceipt(context.Background(), nil, &reply, cb)
+ err := HandleReceipt(context.Background(), "", nil, &reply, cb)
assert.NoError(t, err)
reply.Headers.ReplyType = "TransactionUpdate"
- err = HandleReceipt(context.Background(), nil, &reply, cb)
+ err = HandleReceipt(context.Background(), "", nil, &reply, cb)
assert.NoError(t, err)
reply.Headers.ReplyType = "TransactionFailed"
- err = HandleReceipt(context.Background(), nil, &reply, cb)
+ err = HandleReceipt(context.Background(), "", nil, &reply, cb)
assert.NoError(t, err)
}
@@ -365,7 +365,7 @@ func TestReceiptMarshallingError(t *testing.T) {
cb.SetHandler("ns1", mcb)
mcb.On("OperationUpdate", "ns1", mock.Anything).Return()
- err := HandleReceipt(context.Background(), nil, &reply, cb)
+ err := HandleReceipt(context.Background(), "", nil, &reply, cb)
assert.Error(t, err)
assert.Regexp(t, ".*[^n]marshalling error.*", err)
}
@@ -384,10 +384,19 @@ func TestBadReceipt(t *testing.T) {
data := fftypes.JSONAnyPtr(`{}`)
err := json.Unmarshal(data.Bytes(), &reply)
assert.NoError(t, err)
- err = HandleReceipt(context.Background(), nil, &reply, nil)
+ err = HandleReceipt(context.Background(), "", nil, &reply, nil)
assert.Error(t, err)
}
+func TestWrongNamespaceReceipt(t *testing.T) {
+ var reply BlockchainReceiptNotification
+ data := fftypes.JSONAnyPtr(`{}`)
+ err := json.Unmarshal(data.Bytes(), &reply)
+ assert.NoError(t, err)
+ err = HandleReceipt(context.Background(), "wrong", nil, &reply, nil)
+ assert.NoError(t, err)
+}
+
func TestErrorWrappingConflict(t *testing.T) {
ctx := context.Background()
res := &resty.Response{
@@ -446,3 +455,54 @@ func TestErrorWrappingNonConflict(t *testing.T) {
_, conforms := err.(operations.ConflictError)
assert.False(t, conforms)
}
+
+func TestCallbackBulkOperationUpdate(t *testing.T) {
+ nsOpID := "ns1:" + fftypes.NewUUID().String()
+ nsOpID2 := "ns1:" + fftypes.NewUUID().String()
+
+ mbi := &blockchainmocks.Plugin{}
+ mcb := &coremocks.OperationCallbacks{}
+ cb := NewBlockchainCallbacks()
+ cb.SetOperationalHandler("ns1", mcb)
+
+ mbi.On("Name").Return("utblockchain")
+ mcb.On("BulkOperationUpdates", mock.Anything, mock.MatchedBy(func(updates []*core.OperationUpdate) bool {
+ assert.True(t, updates[0].NamespacedOpID == nsOpID &&
+ updates[0].Status == core.OpStatusSucceeded &&
+ updates[0].BlockchainTXID == "tx1" &&
+ updates[0].ErrorMessage == "err" &&
+ updates[0].Plugin == "utblockchain")
+
+ assert.True(t, updates[1].NamespacedOpID == nsOpID2 &&
+ updates[1].Status == core.OpStatusSucceeded &&
+ updates[1].BlockchainTXID == "tx2" &&
+ updates[1].ErrorMessage == "err" &&
+ updates[1].Plugin == "utblockchain")
+
+ return true
+ })).Return(nil).Once()
+
+ cb.BulkOperationUpdates(context.Background(), "ns1", []*core.OperationUpdate{
+ {
+ NamespacedOpID: nsOpID,
+ Status: core.OpStatusSucceeded,
+ BlockchainTXID: "tx1",
+ ErrorMessage: "err",
+ Output: fftypes.JSONObject{},
+ Plugin: "utblockchain",
+ },
+ {
+ NamespacedOpID: nsOpID2,
+ Status: core.OpStatusSucceeded,
+ BlockchainTXID: "tx2",
+ ErrorMessage: "err",
+ Output: fftypes.JSONObject{},
+ Plugin: "utblockchain",
+ },
+ })
+
+ // No Handler
+ cb.BulkOperationUpdates(context.Background(), "ns2", []*core.OperationUpdate{})
+
+ mcb.AssertExpectations(t)
+}
diff --git a/internal/blockchain/ethereum/ethereum.go b/internal/blockchain/ethereum/ethereum.go
index afa3c2c068..bb3a86ee77 100644
--- a/internal/blockchain/ethereum/ethereum.go
+++ b/internal/blockchain/ethereum/ethereum.go
@@ -21,6 +21,7 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
+ "net/http"
"regexp"
"strconv"
"strings"
@@ -196,7 +197,7 @@ func (e *Ethereum) Init(ctx context.Context, cancelCtx context.CancelFunc, conf
e.streamID = make(map[string]string)
e.closed = make(map[string]chan struct{})
e.wsconn = make(map[string]wsclient.WSClient)
- e.streams = newStreamManager(e.client, e.cache, e.ethconnectConf.GetUint(EthconnectConfigBatchSize), uint(e.ethconnectConf.GetDuration(EthconnectConfigBatchTimeout).Milliseconds()))
+ e.streams = newStreamManager(e.client, e.cache, e.ethconnectConf.GetUint(EthconnectConfigBatchSize), e.ethconnectConf.GetDuration(EthconnectConfigBatchTimeout).Milliseconds())
return nil
}
@@ -513,7 +514,7 @@ func (e *Ethereum) eventLoop(namespace string, wsconn wsclient.WSClient, closed
if !isBatch {
var receipt common.BlockchainReceiptNotification
_ = json.Unmarshal(msgBytes, &receipt)
- err := common.HandleReceipt(ctx, e, &receipt, e.callbacks)
+ err := common.HandleReceipt(ctx, namespace, e, &receipt, e.callbacks)
if err != nil {
l.Errorf("Failed to process receipt: %+v", msgTyped)
}
@@ -1197,7 +1198,7 @@ func (e *Ethereum) GetTransactionStatus(ctx context.Context, operation *core.Ope
SetResult(&statusResponse).
Get(transactionRequestPath)
if err != nil || !res.IsSuccess() {
- if res.StatusCode() == 404 {
+ if res.StatusCode() == http.StatusNotFound {
return nil, nil
}
return nil, common.WrapRESTError(ctx, &resErr, res, err, coremsgs.MsgEthConnectorRESTErr)
@@ -1223,7 +1224,7 @@ func (e *Ethereum) GetTransactionStatus(ctx context.Context, operation *core.Ope
TxHash: statusResponse.GetString("transactionHash"),
Message: statusResponse.GetString("errorMessage"),
ProtocolID: receiptInfo.GetString("protocolId")}
- err := common.HandleReceipt(ctx, e, receipt, e.callbacks)
+ err := common.HandleReceipt(ctx, operation.Namespace, e, receipt, e.callbacks)
if err != nil {
log.L(ctx).Warnf("Failed to handle receipt")
}
diff --git a/internal/blockchain/ethereum/ethereum_test.go b/internal/blockchain/ethereum/ethereum_test.go
index e9c036f3c6..f1e39cfe81 100644
--- a/internal/blockchain/ethereum/ethereum_test.go
+++ b/internal/blockchain/ethereum/ethereum_test.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2024 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -1825,7 +1825,7 @@ func TestHandleReceiptTXSuccess(t *testing.T) {
"transactionIndex": "0"
}`)
- em.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdate) bool {
+ em.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdateAsync) bool {
return update.NamespacedOpID == "ns1:"+operationID.String() &&
update.Status == core.OpStatusSucceeded &&
update.BlockchainTXID == "0x71a38acb7a5d4a970854f6d638ceb1fa10a4b59cbf4ed7674273a1a8dc8b36b8" &&
@@ -1835,7 +1835,7 @@ func TestHandleReceiptTXSuccess(t *testing.T) {
err := json.Unmarshal(data.Bytes(), &reply)
assert.NoError(t, err)
- common.HandleReceipt(context.Background(), e, &reply, e.callbacks)
+ common.HandleReceipt(context.Background(), "ns1", e, &reply, e.callbacks)
em.AssertExpectations(t)
}
@@ -1911,7 +1911,7 @@ func TestHandleReceiptTXUpdateEVMConnect(t *testing.T) {
"updated": "2022-08-03T18:55:43.781941Z"
}`)
- em.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdate) bool {
+ em.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdateAsync) bool {
return update.NamespacedOpID == "ns1:"+operationID.String() &&
update.Status == core.OpStatusPending &&
update.BlockchainTXID == "0x929c898a46762d91e9f4b0b8e2800863dcf4a40f694109dc4cd19dbd334fa4cc" &&
@@ -1922,7 +1922,7 @@ func TestHandleReceiptTXUpdateEVMConnect(t *testing.T) {
assert.NoError(t, err)
expectedReceiptId := "ns1:" + operationID.String()
assert.Equal(t, reply.Headers.ReceiptID, expectedReceiptId)
- common.HandleReceipt(context.Background(), e, &reply, e.callbacks)
+ common.HandleReceipt(context.Background(), "", e, &reply, e.callbacks)
em.AssertExpectations(t)
}
@@ -1955,7 +1955,7 @@ func TestHandleBadPayloadsAndThenReceiptFailure(t *testing.T) {
em := &coremocks.OperationCallbacks{}
e.SetOperationHandler("ns1", em)
- txsu := em.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdate) bool {
+ txsu := em.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdateAsync) bool {
return update.NamespacedOpID == "ns1:"+operationID.String() &&
update.Status == core.OpStatusFailed &&
update.ErrorMessage == "Packing arguments for method 'broadcastBatch': abi: cannot use [3]uint8 as type [32]uint8 as argument" &&
@@ -1987,7 +1987,7 @@ func TestHandleMsgBatchBadData(t *testing.T) {
data := fftypes.JSONAnyPtr(`{}`)
err := json.Unmarshal(data.Bytes(), &reply)
assert.NoError(t, err)
- common.HandleReceipt(context.Background(), e, &reply, e.callbacks)
+ common.HandleReceipt(context.Background(), "", e, &reply, e.callbacks)
}
func TestFormatNil(t *testing.T) {
diff --git a/internal/blockchain/ethereum/eventstream.go b/internal/blockchain/ethereum/eventstream.go
index 078ad95107..30cf4fb32a 100644
--- a/internal/blockchain/ethereum/eventstream.go
+++ b/internal/blockchain/ethereum/eventstream.go
@@ -21,6 +21,7 @@ import (
"crypto/sha256"
"encoding/hex"
"fmt"
+ "net/http"
"strconv"
"strings"
@@ -38,7 +39,7 @@ type streamManager struct {
client *resty.Client
cache cache.CInterface
batchSize uint
- batchTimeout uint
+ batchTimeout int64
}
type eventStream struct {
@@ -46,7 +47,7 @@ type eventStream struct {
Name string `json:"name"`
ErrorHandling string `json:"errorHandling"`
BatchSize uint `json:"batchSize"`
- BatchTimeoutMS uint `json:"batchTimeoutMS"`
+ BatchTimeoutMS int64 `json:"batchTimeoutMS"`
Type string `json:"type"`
WebSocket eventStreamWebsocket `json:"websocket"`
Timestamps bool `json:"timestamps"`
@@ -73,7 +74,7 @@ type subscriptionCheckpoint struct {
Catchup bool `json:"catchup,omitempty"`
}
-func newStreamManager(client *resty.Client, cache cache.CInterface, batchSize, batchTimeout uint) *streamManager {
+func newStreamManager(client *resty.Client, cache cache.CInterface, batchSize uint, batchTimeout int64) *streamManager {
return &streamManager{
client: client,
cache: cache,
@@ -93,7 +94,7 @@ func (s *streamManager) getEventStreams(ctx context.Context) (streams []*eventSt
return streams, nil
}
-func buildEventStream(topic string, batchSize, batchTimeout uint) *eventStream {
+func buildEventStream(topic string, batchSize uint, batchTimeout int64) *eventStream {
return &eventStream{
Name: topic,
ErrorHandling: "block",
@@ -120,7 +121,7 @@ func (s *streamManager) createEventStream(ctx context.Context, topic string) (*e
return stream, nil
}
-func (s *streamManager) updateEventStream(ctx context.Context, topic string, batchSize, batchTimeout uint, eventStreamID string) (*eventStream, error) {
+func (s *streamManager) updateEventStream(ctx context.Context, topic string, batchSize uint, batchTimeout int64, eventStreamID string) (*eventStream, error) {
stream := buildEventStream(topic, batchSize, batchTimeout)
res, err := s.client.R().
SetContext(ctx).
@@ -161,7 +162,7 @@ func (s *streamManager) deleteEventStream(ctx context.Context, esID string, okNo
SetContext(ctx).
Delete("/eventstreams/" + esID)
if err != nil || !res.IsSuccess() {
- if okNotFound && res.StatusCode() == 404 {
+ if okNotFound && res.StatusCode() == http.StatusNotFound {
return nil
}
return ffresty.WrapRestErr(ctx, res, err, coremsgs.MsgEthConnectorRESTErr)
@@ -186,7 +187,7 @@ func (s *streamManager) getSubscription(ctx context.Context, subID string, okNot
SetResult(&sub).
Get(fmt.Sprintf("/subscriptions/%s", subID))
if err != nil || !res.IsSuccess() {
- if okNotFound && res.StatusCode() == 404 {
+ if okNotFound && res.StatusCode() == http.StatusNotFound {
return nil, nil
}
return nil, ffresty.WrapRestErr(ctx, res, err, coremsgs.MsgEthConnectorRESTErr)
@@ -282,7 +283,7 @@ func (s *streamManager) deleteSubscription(ctx context.Context, subID string, ok
SetContext(ctx).
Delete("/subscriptions/" + subID)
if err != nil || !res.IsSuccess() {
- if okNotFound && res.StatusCode() == 404 {
+ if okNotFound && res.StatusCode() == http.StatusNotFound {
return nil
}
return ffresty.WrapRestErr(ctx, res, err, coremsgs.MsgEthConnectorRESTErr)
diff --git a/internal/blockchain/fabric/eventstream.go b/internal/blockchain/fabric/eventstream.go
index 48d1b72712..ee719b346c 100644
--- a/internal/blockchain/fabric/eventstream.go
+++ b/internal/blockchain/fabric/eventstream.go
@@ -19,6 +19,7 @@ package fabric
import (
"context"
"fmt"
+ "net/http"
"strconv"
"strings"
@@ -36,7 +37,7 @@ type streamManager struct {
signer string
cache cache.CInterface
batchSize uint
- batchTimeoutMS uint
+ batchTimeoutMS int64
}
type eventStream struct {
@@ -44,7 +45,7 @@ type eventStream struct {
Name string `json:"name"`
ErrorHandling string `json:"errorHandling"`
BatchSize uint `json:"batchSize"`
- BatchTimeoutMS uint `json:"batchTimeoutMS"`
+ BatchTimeoutMS int64 `json:"batchTimeoutMS"`
Type string `json:"type"`
WebSocket eventStreamWebsocket `json:"websocket"`
Timestamps bool `json:"timestamps"`
@@ -65,7 +66,7 @@ type eventFilter struct {
EventFilter string `json:"eventFilter"`
}
-func newStreamManager(client *resty.Client, signer string, cache cache.CInterface, batchSize, batchTimeout uint) *streamManager {
+func newStreamManager(client *resty.Client, signer string, cache cache.CInterface, batchSize uint, batchTimeout int64) *streamManager {
return &streamManager{
client: client,
signer: signer,
@@ -86,7 +87,7 @@ func (s *streamManager) getEventStreams(ctx context.Context) (streams []*eventSt
return streams, nil
}
-func buildEventStream(topic string, batchSize, batchTimeout uint) *eventStream {
+func buildEventStream(topic string, batchSize uint, batchTimeout int64) *eventStream {
return &eventStream{
Name: topic,
ErrorHandling: "block",
@@ -137,7 +138,7 @@ func (s *streamManager) deleteEventStream(ctx context.Context, esID string, okNo
SetContext(ctx).
Delete("/eventstreams/" + esID)
if err != nil || !res.IsSuccess() {
- if okNotFound && res.StatusCode() == 404 {
+ if okNotFound && res.StatusCode() == http.StatusNotFound {
return nil
}
return ffresty.WrapRestErr(ctx, res, err, coremsgs.MsgFabconnectRESTErr)
@@ -162,7 +163,7 @@ func (s *streamManager) getSubscription(ctx context.Context, subID string, okNot
SetResult(&sub).
Get(fmt.Sprintf("/subscriptions/%s", subID))
if err != nil || !res.IsSuccess() {
- if okNotFound && res.StatusCode() == 404 {
+ if okNotFound && res.StatusCode() == http.StatusNotFound {
return nil, nil
}
return nil, ffresty.WrapRestErr(ctx, res, err, coremsgs.MsgFabconnectRESTErr)
@@ -261,7 +262,7 @@ func (s *streamManager) deleteSubscription(ctx context.Context, subID string, ok
SetContext(ctx).
Delete("/subscriptions/" + subID)
if err != nil || !res.IsSuccess() {
- if okNotFound && res.StatusCode() == 404 {
+ if okNotFound && res.StatusCode() == http.StatusNotFound {
return nil
}
return ffresty.WrapRestErr(ctx, res, err, coremsgs.MsgFabconnectRESTErr)
diff --git a/internal/blockchain/fabric/fabric.go b/internal/blockchain/fabric/fabric.go
index 574e5d8e94..467f531ebb 100644
--- a/internal/blockchain/fabric/fabric.go
+++ b/internal/blockchain/fabric/fabric.go
@@ -22,6 +22,7 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
+ "net/http"
"regexp"
"strings"
@@ -242,7 +243,7 @@ func (f *Fabric) Init(ctx context.Context, cancelCtx context.CancelFunc, conf co
f.streamID = make(map[string]string)
f.closed = make(map[string]chan struct{})
f.wsconn = make(map[string]wsclient.WSClient)
- f.streams = newStreamManager(f.client, f.signer, f.cache, f.fabconnectConf.GetUint(FabconnectConfigBatchSize), uint(f.fabconnectConf.GetDuration(FabconnectConfigBatchTimeout).Milliseconds()))
+ f.streams = newStreamManager(f.client, f.signer, f.cache, f.fabconnectConf.GetUint(FabconnectConfigBatchSize), f.fabconnectConf.GetDuration(FabconnectConfigBatchTimeout).Milliseconds())
return nil
}
@@ -540,7 +541,7 @@ func (f *Fabric) eventLoop(namespace string, wsconn wsclient.WSClient, closed ch
var receipt common.BlockchainReceiptNotification
_ = json.Unmarshal(msgBytes, &receipt)
- err := common.HandleReceipt(ctx, f, &receipt, f.callbacks)
+ err := common.HandleReceipt(ctx, namespace, f, &receipt, f.callbacks)
if err != nil {
l.Errorf("Failed to process receipt: %+v", msgTyped)
}
@@ -1118,7 +1119,7 @@ func (f *Fabric) GetTransactionStatus(ctx context.Context, operation *core.Opera
SetQueryParam("fly-signer", defaultSigner).
Get(transactionRequestPath)
if err != nil || !res.IsSuccess() {
- if res.StatusCode() == 404 {
+ if res.StatusCode() == http.StatusNotFound {
return nil, nil
}
return nil, common.WrapRESTError(ctx, &resErr, res, err, coremsgs.MsgFabconnectRESTErr)
diff --git a/internal/blockchain/fabric/fabric_test.go b/internal/blockchain/fabric/fabric_test.go
index a839fa9ee9..0480abc565 100644
--- a/internal/blockchain/fabric/fabric_test.go
+++ b/internal/blockchain/fabric/fabric_test.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2024 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -50,9 +50,11 @@ import (
"github.com/stretchr/testify/mock"
)
-var utConfig = config.RootSection("fab_unit_tests")
-var utFabconnectConf = utConfig.SubSection(FabconnectConfigKey)
-var signer = "orgMSP::x509::CN=signer001,OU=client::CN=fabric-ca"
+var (
+ utConfig = config.RootSection("fab_unit_tests")
+ utFabconnectConf = utConfig.SubSection(FabconnectConfigKey)
+ signer = "orgMSP::x509::CN=signer001,OU=client::CN=fabric-ca"
+)
func resetConf(e *Fabric) {
coreconfig.Reset()
@@ -262,7 +264,6 @@ func TestBadTLS(t *testing.T) {
}
func TestInitAllNewStreamsAndWSEvent(t *testing.T) {
-
log.SetLevel("trace")
e, cancel := newTestFabric()
defer cancel()
@@ -336,11 +337,9 @@ func TestInitAllNewStreamsAndWSEvent(t *testing.T) {
fromServer <- `!json`
fromServer <- `{"not": "a reply"}`
fromServer <- `42`
-
}
func TestWSInitFail(t *testing.T) {
-
e, cancel := newTestFabric()
defer cancel()
@@ -357,7 +356,6 @@ func TestWSInitFail(t *testing.T) {
err = e.StartNamespace(e.ctx, "ns1")
assert.Regexp(t, "FF00149", err)
-
}
func TestCacheInitFail(t *testing.T) {
@@ -886,7 +884,6 @@ func TestInitNewConfig(t *testing.T) {
}
func TestStreamQueryError(t *testing.T) {
-
e, cancel := newTestFabric()
defer cancel()
@@ -912,11 +909,9 @@ func TestStreamQueryError(t *testing.T) {
err = e.StartNamespace(e.ctx, "ns1")
assert.Regexp(t, "FF10284.*pop", err)
-
}
func TestStreamCreateError(t *testing.T) {
-
e, cancel := newTestFabric()
defer cancel()
@@ -944,11 +939,9 @@ func TestStreamCreateError(t *testing.T) {
err = e.StartNamespace(e.ctx, "ns1")
assert.Regexp(t, "FF10284.*pop", err)
-
}
func TestEnsureStreamDelete(t *testing.T) {
-
e, cancel := newTestFabric()
defer cancel()
@@ -985,7 +978,6 @@ func TestEnsureStreamDelete(t *testing.T) {
}
func TestEnsureStreamDeleteFail(t *testing.T) {
-
e, cancel := newTestFabric()
defer cancel()
@@ -1050,7 +1042,6 @@ func TestDeleteStreamOKNotFound(t *testing.T) {
}
func TestSubQueryCreateError(t *testing.T) {
-
e, cancel := newTestFabric()
defer cancel()
@@ -1094,11 +1085,9 @@ func TestSubQueryCreateError(t *testing.T) {
e.streamID["ns1"] = "es12345"
_, err = e.AddFireflySubscription(e.ctx, ns, contract, "")
assert.Regexp(t, "FF10284.*pop", err)
-
}
func TestSubQueryCreate(t *testing.T) {
-
e, cancel := newTestFabric()
defer cancel()
@@ -1142,11 +1131,9 @@ func TestSubQueryCreate(t *testing.T) {
e.streamID["ns1"] = "es12345"
_, err = e.AddFireflySubscription(e.ctx, ns, contract, "")
assert.NoError(t, err)
-
}
func TestSubmitBatchPinOK(t *testing.T) {
-
e, cancel := newTestFabric()
defer cancel()
httpmock.ActivateNonDefault(e.client.GetClient())
@@ -1186,11 +1173,9 @@ func TestSubmitBatchPinOK(t *testing.T) {
err := e.SubmitBatchPin(context.Background(), "", "ns1", signer, batch, location)
assert.NoError(t, err)
-
}
func TestSubmitBatchPinV1(t *testing.T) {
-
e, cancel := newTestFabric()
defer cancel()
httpmock.ActivateNonDefault(e.client.GetClient())
@@ -1230,11 +1215,9 @@ func TestSubmitBatchPinV1(t *testing.T) {
err := e.SubmitBatchPin(context.Background(), "", "ns1", signer, batch, location)
assert.NoError(t, err)
-
}
func TestSubmitBatchPinBadLocation(t *testing.T) {
-
e, _ := newTestFabric()
signer := "signer001"
@@ -1259,7 +1242,6 @@ func TestSubmitBatchPinBadLocation(t *testing.T) {
}
func TestSubmitBatchEmptyPayloadRef(t *testing.T) {
-
e, cancel := newTestFabric()
defer cancel()
httpmock.ActivateNonDefault(e.client.GetClient())
@@ -1298,11 +1280,9 @@ func TestSubmitBatchEmptyPayloadRef(t *testing.T) {
err := e.SubmitBatchPin(context.Background(), "", "ns1", signer, batch, location)
assert.NoError(t, err)
-
}
func TestSubmitBatchPinVersionFail(t *testing.T) {
-
e, cancel := newTestFabric()
defer cancel()
httpmock.ActivateNonDefault(e.client.GetClient())
@@ -1331,11 +1311,9 @@ func TestSubmitBatchPinVersionFail(t *testing.T) {
err := e.SubmitBatchPin(context.Background(), "", "ns1", signer, batch, location)
assert.Regexp(t, "FF10284.*pop", err)
-
}
func TestSubmitBatchPinFail(t *testing.T) {
-
e, cancel := newTestFabric()
defer cancel()
httpmock.ActivateNonDefault(e.client.GetClient())
@@ -1367,11 +1345,9 @@ func TestSubmitBatchPinFail(t *testing.T) {
err := e.SubmitBatchPin(context.Background(), "", "ns1", signer, batch, location)
assert.Regexp(t, "FF10284.*pop", err)
-
}
func TestSubmitBatchPinError(t *testing.T) {
-
e, cancel := newTestFabric()
defer cancel()
httpmock.ActivateNonDefault(e.client.GetClient())
@@ -1405,7 +1381,6 @@ func TestSubmitBatchPinError(t *testing.T) {
err := e.SubmitBatchPin(context.Background(), "", "ns1", signer, batch, location)
assert.Regexp(t, "FF10284.*Invalid", err)
-
}
func TestResolveSignerBlank(t *testing.T) {
@@ -1425,7 +1400,6 @@ func TestResolveFullIDSigner(t *testing.T) {
signKey, err := e.ResolveSigningKey(context.Background(), id, blockchain.ResolveKeyIntentSign)
assert.NoError(t, err)
assert.Equal(t, "org1MSP::x509::CN=admin,OU=client::CN=fabric-ca-server", signKey)
-
}
func TestResolveSigner(t *testing.T) {
@@ -1458,7 +1432,7 @@ func TestResolveSignerFailedFabricCARequest(t *testing.T) {
responder, _ := httpmock.NewJsonResponder(503, res)
httpmock.RegisterResponder("GET", `http://localhost:12345/identities/signer001`, responder)
_, err := e.ResolveSigningKey(context.Background(), "signer001", blockchain.ResolveKeyIntentSign)
- assert.EqualError(t, err, "FF10284: Error from fabconnect: %!!(MISSING)s()")
+ assert.Contains(t, err.Error(), "FF10284: Error from fabconnect:")
}
func TestResolveSignerBadECertReturned(t *testing.T) {
@@ -1572,7 +1546,6 @@ func TestHandleMessageBatchPinOK(t *testing.T) {
assert.Equal(t, "19b82093de5ce92a01e333048e877e2374354bf846dd034864ef6ffbd6438771", b.Batch.Contexts[1].String())
em.AssertExpectations(t)
-
}
func TestHandleMessageBatchPinMissingChaincodeID(t *testing.T) {
@@ -1615,7 +1588,6 @@ func TestHandleMessageBatchPinMissingChaincodeID(t *testing.T) {
assert.NoError(t, err)
err = e.handleMessageBatch(context.Background(), events)
assert.Regexp(t, "FF10310", err)
-
}
func TestHandleMessageUnknownEventName(t *testing.T) {
@@ -1806,7 +1778,7 @@ func TestHandleReceiptTXSuccess(t *testing.T) {
"receivedAt": 1630033474675
}`)
- em.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdate) bool {
+ em.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdateAsync) bool {
return update.NamespacedOpID == "ns1:"+operationID.String() &&
update.Status == core.OpStatusSucceeded &&
update.BlockchainTXID == "ce79343000e851a0c742f63a733ce19a5f8b9ce1c719b6cecd14f01bcf81fff2" &&
@@ -1815,7 +1787,7 @@ func TestHandleReceiptTXSuccess(t *testing.T) {
err := json.Unmarshal(data, &reply)
assert.NoError(t, err)
- common.HandleReceipt(context.Background(), e, &reply, e.callbacks)
+ common.HandleReceipt(context.Background(), "ns1", e, &reply, e.callbacks)
em.AssertExpectations(t)
}
@@ -1836,7 +1808,7 @@ func TestHandleReceiptNoRequestID(t *testing.T) {
data := []byte(`{}`)
err := json.Unmarshal(data, &reply)
assert.NoError(t, err)
- common.HandleReceipt(context.Background(), e, &reply, e.callbacks)
+ common.HandleReceipt(context.Background(), "", e, &reply, e.callbacks)
}
func TestHandleReceiptFailedTx(t *testing.T) {
@@ -1867,7 +1839,7 @@ func TestHandleReceiptFailedTx(t *testing.T) {
"transactionHash": "ce79343000e851a0c742f63a733ce19a5f8b9ce1c719b6cecd14f01bcf81fff2"
}`)
- em.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdate) bool {
+ em.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdateAsync) bool {
return update.NamespacedOpID == "ns1:"+operationID.String() &&
update.Status == core.OpStatusFailed &&
update.BlockchainTXID == "ce79343000e851a0c742f63a733ce19a5f8b9ce1c719b6cecd14f01bcf81fff2" &&
@@ -1876,7 +1848,7 @@ func TestHandleReceiptFailedTx(t *testing.T) {
err := json.Unmarshal(data, &reply)
assert.NoError(t, err)
- common.HandleReceipt(context.Background(), e, &reply, e.callbacks)
+ common.HandleReceipt(context.Background(), "", e, &reply, e.callbacks)
em.AssertExpectations(t)
}
@@ -3042,7 +3014,6 @@ func TestHandleNetworkAction(t *testing.T) {
assert.NoError(t, err)
em.AssertExpectations(t)
-
}
func TestHandleNetworkActionFail(t *testing.T) {
@@ -3084,7 +3055,6 @@ func TestHandleNetworkActionFail(t *testing.T) {
assert.EqualError(t, err, "pop")
em.AssertExpectations(t)
-
}
func TestGetNetworkVersion(t *testing.T) {
@@ -3244,7 +3214,6 @@ func TestConvertDeprecatedContractConfigNoChannel(t *testing.T) {
}
func TestSubmitNetworkAction(t *testing.T) {
-
e, cancel := newTestFabric()
defer cancel()
httpmock.ActivateNonDefault(e.client.GetClient())
@@ -3275,7 +3244,6 @@ func TestSubmitNetworkAction(t *testing.T) {
}
func TestSubmitNetworkActionV1(t *testing.T) {
-
e, cancel := newTestFabric()
defer cancel()
httpmock.ActivateNonDefault(e.client.GetClient())
@@ -3334,7 +3302,6 @@ func TestSubmitNetworkActionBadLocation(t *testing.T) {
}
func TestSubmitNetworkActionVersionError(t *testing.T) {
-
e, cancel := newTestFabric()
defer cancel()
httpmock.ActivateNonDefault(e.client.GetClient())
diff --git a/internal/blockchain/tezos/eventstream.go b/internal/blockchain/tezos/eventstream.go
index f48f93d094..63bdf5af7b 100644
--- a/internal/blockchain/tezos/eventstream.go
+++ b/internal/blockchain/tezos/eventstream.go
@@ -22,6 +22,7 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
+ "net/http"
"github.com/go-resty/resty/v2"
"github.com/hyperledger/firefly-common/pkg/ffresty"
@@ -36,7 +37,7 @@ type streamManager struct {
client *resty.Client
cache cache.CInterface
batchSize uint
- batchTimeout uint
+ batchTimeout int64
}
type eventStream struct {
@@ -44,7 +45,7 @@ type eventStream struct {
Name string `json:"name"`
ErrorHandling string `json:"errorHandling"`
BatchSize uint `json:"batchSize"`
- BatchTimeoutMS uint `json:"batchTimeoutMS"`
+ BatchTimeoutMS int64 `json:"batchTimeoutMS"`
Type string `json:"type"`
Timestamps bool `json:"timestamps"`
}
@@ -64,7 +65,7 @@ type eventFilter struct {
EventFilter string `json:"eventFilter"`
}
-func newStreamManager(client *resty.Client, cache cache.CInterface, batchSize, batchTimeout uint) *streamManager {
+func newStreamManager(client *resty.Client, cache cache.CInterface, batchSize uint, batchTimeout int64) *streamManager {
return &streamManager{
client: client,
cache: cache,
@@ -84,7 +85,7 @@ func (s *streamManager) getEventStreams(ctx context.Context) (streams []*eventSt
return streams, nil
}
-func buildEventStream(topic string, batchSize, batchTimeout uint) *eventStream {
+func buildEventStream(topic string, batchSize uint, batchTimeout int64) *eventStream {
return &eventStream{
Name: topic,
ErrorHandling: "block",
@@ -108,7 +109,7 @@ func (s *streamManager) createEventStream(ctx context.Context, topic string) (*e
return stream, nil
}
-func (s *streamManager) updateEventStream(ctx context.Context, topic string, batchSize, batchTimeout uint, eventStreamID string) (*eventStream, error) {
+func (s *streamManager) updateEventStream(ctx context.Context, topic string, batchSize uint, batchTimeout int64, eventStreamID string) (*eventStream, error) {
stream := buildEventStream(topic, batchSize, batchTimeout)
res, err := s.client.R().
SetContext(ctx).
@@ -155,7 +156,7 @@ func (s *streamManager) getSubscription(ctx context.Context, subID string, okNot
SetResult(&sub).
Get(fmt.Sprintf("/subscriptions/%s", subID))
if err != nil || !res.IsSuccess() {
- if okNotFound && res.StatusCode() == 404 {
+ if okNotFound && res.StatusCode() == http.StatusNotFound {
return nil, nil
}
return nil, ffresty.WrapRestErr(ctx, res, err, coremsgs.MsgTezosconnectRESTErr)
@@ -206,7 +207,7 @@ func (s *streamManager) deleteSubscription(ctx context.Context, subID string, ok
SetContext(ctx).
Delete("/subscriptions/" + subID)
if err != nil || !res.IsSuccess() {
- if okNotFound && res.StatusCode() == 404 {
+ if okNotFound && res.StatusCode() == http.StatusNotFound {
return nil
}
return ffresty.WrapRestErr(ctx, res, err, coremsgs.MsgTezosconnectRESTErr)
diff --git a/internal/blockchain/tezos/tezos.go b/internal/blockchain/tezos/tezos.go
index 8dd1fb8d4f..a591b5658f 100644
--- a/internal/blockchain/tezos/tezos.go
+++ b/internal/blockchain/tezos/tezos.go
@@ -20,6 +20,7 @@ import (
"context"
"encoding/json"
"fmt"
+ "net/http"
"regexp"
"blockwatch.cc/tzgo/micheline"
@@ -203,7 +204,7 @@ func (t *Tezos) Init(ctx context.Context, cancelCtx context.CancelFunc, conf con
}
t.cache = cache
- t.streams = newStreamManager(t.client, t.cache, t.tezosconnectConf.GetUint(TezosconnectConfigBatchSize), uint(t.tezosconnectConf.GetDuration(TezosconnectConfigBatchTimeout).Milliseconds()))
+ t.streams = newStreamManager(t.client, t.cache, t.tezosconnectConf.GetUint(TezosconnectConfigBatchSize), t.tezosconnectConf.GetDuration(TezosconnectConfigBatchTimeout).Milliseconds())
t.backgroundStart = t.tezosconnectConf.GetBool(TezosconnectBackgroundStart)
if t.backgroundStart {
@@ -564,7 +565,7 @@ func (t *Tezos) GetTransactionStatus(ctx context.Context, operation *core.Operat
SetResult(&statusResponse).
Get(transactionRequestPath)
if err != nil || !res.IsSuccess() {
- if res.StatusCode() == 404 {
+ if res.StatusCode() == http.StatusNotFound {
return nil, nil
}
return nil, common.WrapRESTError(ctx, &resErr, res, err, coremsgs.MsgTezosconnectRESTErr)
@@ -591,7 +592,7 @@ func (t *Tezos) GetTransactionStatus(ctx context.Context, operation *core.Operat
TxHash: statusResponse.GetString("transactionHash"),
Message: statusResponse.GetString("errorMessage"),
ProtocolID: receiptInfo.GetString("protocolId")}
- err := common.HandleReceipt(ctx, t, receipt, t.callbacks)
+ err := common.HandleReceipt(ctx, operation.Namespace, t, receipt, t.callbacks)
if err != nil {
log.L(ctx).Warnf("Failed to handle receipt")
}
@@ -822,7 +823,7 @@ func (t *Tezos) eventLoop() {
var receipt common.BlockchainReceiptNotification
_ = json.Unmarshal(msgBytes, &receipt)
- err := common.HandleReceipt(ctx, t, &receipt, t.callbacks)
+ err := common.HandleReceipt(ctx, "", t, &receipt, t.callbacks) // TODO: should be specific to a namespace
if err != nil {
l.Errorf("Failed to process receipt: %+v", msgTyped)
}
diff --git a/internal/blockchain/tezos/tezos_test.go b/internal/blockchain/tezos/tezos_test.go
index 9b545a4cab..6df9b89ffd 100644
--- a/internal/blockchain/tezos/tezos_test.go
+++ b/internal/blockchain/tezos/tezos_test.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2024 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -685,7 +685,7 @@ func TestHandleReceiptTXSuccess(t *testing.T) {
}
}`)
- tm.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdate) bool {
+ tm.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdateAsync) bool {
return update.NamespacedOpID == "ns1:"+operationID.String() &&
update.Status == core.OpStatusSucceeded &&
update.BlockchainTXID == "ooGcrcazgcGBrY1iym329ovV13MnWrTmV1fttCwWKH5DiYUQsiq" &&
@@ -695,7 +695,7 @@ func TestHandleReceiptTXSuccess(t *testing.T) {
err := json.Unmarshal(data.Bytes(), &reply)
assert.NoError(t, err)
- common.HandleReceipt(context.Background(), tz, &reply, tz.callbacks)
+ common.HandleReceipt(context.Background(), "", tz, &reply, tz.callbacks)
tm.AssertExpectations(t)
}
@@ -769,7 +769,7 @@ func TestHandleReceiptTXUpdateTezosConnect(t *testing.T) {
"updated": "2023-09-10T14:49:36.030604Z"
}`)
- tm.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdate) bool {
+ tm.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdateAsync) bool {
return update.NamespacedOpID == "ns1:"+operationID.String() &&
update.Status == core.OpStatusPending &&
update.BlockchainTXID == "onhZJDmz5JihnW1RaZ96f17FgUBv3GoERkRECK3XVFt1kL5E6Yy" &&
@@ -780,7 +780,7 @@ func TestHandleReceiptTXUpdateTezosConnect(t *testing.T) {
assert.NoError(t, err)
expectedReceiptId := "ns1:" + operationID.String()
assert.Equal(t, reply.Headers.ReceiptID, expectedReceiptId)
- common.HandleReceipt(context.Background(), tz, &reply, tz.callbacks)
+ common.HandleReceipt(context.Background(), "", tz, &reply, tz.callbacks)
tm.AssertExpectations(t)
}
@@ -797,7 +797,7 @@ func TestHandleMsgBatchBadData(t *testing.T) {
data := fftypes.JSONAnyPtr(`{}`)
err := json.Unmarshal(data.Bytes(), &reply)
assert.NoError(t, err)
- common.HandleReceipt(context.Background(), tz, &reply, tz.callbacks)
+ common.HandleReceipt(context.Background(), "", tz, &reply, tz.callbacks)
}
func TestAddSubscription(t *testing.T) {
diff --git a/internal/broadcast/manager.go b/internal/broadcast/manager.go
index 415585bbb5..c0c8ff696c 100644
--- a/internal/broadcast/manager.go
+++ b/internal/broadcast/manager.go
@@ -99,7 +99,7 @@ func NewBroadcastManager(ctx context.Context, ns *core.Namespace, di database.Pl
if ba != nil && mult != nil {
bo := batch.DispatcherOptions{
BatchType: core.BatchTypeBroadcast,
- BatchMaxSize: config.GetUint(coreconfig.BroadcastBatchSize),
+ BatchMaxSize: config.GetInt(coreconfig.BroadcastBatchSize),
BatchMaxBytes: bm.maxBatchPayloadLength,
BatchTimeout: config.GetDuration(coreconfig.BroadcastBatchTimeout),
DisposeTimeout: config.GetDuration(coreconfig.BroadcastBatchAgentTimeout),
diff --git a/internal/coreconfig/coreconfig.go b/internal/coreconfig/coreconfig.go
index 401f69c1ac..ad6428ee89 100644
--- a/internal/coreconfig/coreconfig.go
+++ b/internal/coreconfig/coreconfig.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2024 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -287,10 +287,14 @@ var (
MessageWriterBatchTimeout = ffc("message.writer.batchTimeout")
// MessageWriterBatchMaxInserts
MessageWriterBatchMaxInserts = ffc("message.writer.batchMaxInserts")
- // MetricsEnabled determines whether metrics will be instrumented and if the metrics server will be enabled or not
- MetricsEnabled = ffc("metrics.enabled")
+ // MetricsEnabled - deprecated, use monitoring.enabled
+ DeprecatedMetricsEnabled = ffc("metrics.enabled")
+ // MetricsPath - deprecated, use monitoring.metricsPath
+ DeprecatedMetricsPath = ffc("metrics.path")
+ // Monitoring determines whether monitoring routes will be enabled, which contains metrics instruments
+ MonitoringEnabled = ffc("monitoring.enabled")
// MetricsPath determines what path to serve the Prometheus metrics from
- MetricsPath = ffc("metrics.path")
+ MonitoringMetricsPath = ffc("monitoring.metricsPath")
// NamespacesDefault is the default namespace - must be in the predefines list
NamespacesDefault = ffc("namespaces.default")
// NamespacesPredefined is a list of namespaces to ensure exists, without requiring a broadcast from the network
diff --git a/internal/coremsgs/en_config_descriptions.go b/internal/coremsgs/en_config_descriptions.go
index 1015b75710..3995499d93 100644
--- a/internal/coremsgs/en_config_descriptions.go
+++ b/internal/coremsgs/en_config_descriptions.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2024 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -320,13 +320,21 @@ var (
ConfigTransactionWriterBatchTimeout = ffc("config.transaction.writer.batchTimeout", "How long to wait for more transactions to arrive before flushing the batch", i18n.TimeDurationType)
ConfigTransactionWriterCount = ffc("config.transaction.writer.count", "The number of message writer workers", i18n.IntType)
- ConfigMetricsAddress = ffc("config.metrics.address", "The IP address on which the metrics HTTP API should listen", i18n.IntType)
- ConfigMetricsEnabled = ffc("config.metrics.enabled", "Enables the metrics API", i18n.BooleanType)
- ConfigMetricsPath = ffc("config.metrics.path", "The path from which to serve the Prometheus metrics", i18n.StringType)
- ConfigMetricsPort = ffc("config.metrics.port", "The port on which the metrics HTTP API should listen", i18n.IntType)
- ConfigMetricsPublicURL = ffc("config.metrics.publicURL", "The fully qualified public URL for the metrics API. This is used for building URLs in HTTP responses and in OpenAPI Spec generation", urlStringType)
- ConfigMetricsReadTimeout = ffc("config.metrics.readTimeout", "The maximum time to wait when reading from an HTTP connection", i18n.TimeDurationType)
- ConfigMetricsWriteTimeout = ffc("config.metrics.writeTimeout", "The maximum time to wait when writing to an HTTP connection", i18n.TimeDurationType)
+ DeprecatedConfigMetricsAddress = ffc("config.metrics.address", "Deprecated - use monitoring.address instead", i18n.IntType)
+ DeprecatedConfigMetricsEnabled = ffc("config.metrics.enabled", "Deprecated - use monitoring.enabled instead", i18n.BooleanType)
+ DeprecatedConfigMetricsPath = ffc("config.metrics.path", "Deprecated - use monitoring.metricsPath instead", i18n.StringType)
+ DeprecatedConfigMetricsPort = ffc("config.metrics.port", "Deprecated - use monitoring.port instead", i18n.IntType)
+ DeprecatedConfigMetricsPublicURL = ffc("config.metrics.publicURL", "Deprecated - use monitoring.publicURL instead", urlStringType)
+ DeprecatedConfigMetricsReadTimeout = ffc("config.metrics.readTimeout", "Deprecated - use monitoring.readTimeout instead", i18n.TimeDurationType)
+ DeprecatedConfigMetricsWriteTimeout = ffc("config.metrics.writeTimeout", "Deprecated - use monitoring.writeTimeout instead", i18n.TimeDurationType)
+
+ ConfigMetricsAddress = ffc("config.monitoring.address", "The IP address on which the metrics HTTP API should listen", i18n.IntType)
+ ConfigMetricsEnabled = ffc("config.monitoring.enabled", "Enables the metrics API", i18n.BooleanType)
+ ConfigMetricsPath = ffc("config.monitoring.metricsPath", "The path from which to serve the Prometheus metrics", i18n.StringType)
+ ConfigMetricsPort = ffc("config.monitoring.port", "The port on which the metrics HTTP API should listen", i18n.IntType)
+ ConfigMetricsPublicURL = ffc("config.monitoring.publicURL", "The fully qualified public URL for the metrics API. This is used for building URLs in HTTP responses and in OpenAPI Spec generation", urlStringType)
+ ConfigMetricsReadTimeout = ffc("config.monitoring.readTimeout", "The maximum time to wait when reading from an HTTP connection", i18n.TimeDurationType)
+ ConfigMetricsWriteTimeout = ffc("config.monitoring.writeTimeout", "The maximum time to wait when writing to an HTTP connection", i18n.TimeDurationType)
ConfigNamespacesDefault = ffc("config.namespaces.default", "The default namespace - must be in the predefined list", i18n.StringType)
ConfigNamespacesPredefined = ffc("config.namespaces.predefined", "A list of namespaces to ensure exists, without requiring a broadcast from the network", "List "+i18n.StringType)
diff --git a/internal/coremsgs/en_error_messages.go b/internal/coremsgs/en_error_messages.go
index 8cccd5c344..78243541a2 100644
--- a/internal/coremsgs/en_error_messages.go
+++ b/internal/coremsgs/en_error_messages.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2024 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -316,4 +316,9 @@ var (
MsgFiltersEmpty = ffe("FF10475", "No filters specified in contract listener: %s.", 500)
MsgContractListenerBlockchainFilterLimit = ffe("FF10476", "Blockchain plugin only supports one filter for contract listener: %s.", 500)
MsgDuplicateContractListenerFilterLocation = ffe("FF10477", "Duplicate filter provided for contract listener for location", 400)
+ MsgInvalidNamespaceForOperationUpdate = ffe("FF10478", "Received different namespace for operation update '%s' than expected for manager '%s'")
+ MsgEmptyPluginForOperationUpdate = ffe("FF10479", "Received empty plugin for operation update '%s'")
+ MsgInvalidIdentityPatch = ffe("FF10480", "A profile must be provided when updating an identity", 400)
+ MsgNodeNotProvidedForCheck = ffe("FF10481", "Node not provided for check", 500)
+ MsgNodeMissingProfile = ffe("FF10482", "Node provided for check does not have a profile", 500)
)
diff --git a/internal/coremsgs/en_struct_descriptions.go b/internal/coremsgs/en_struct_descriptions.go
index 208df0d3b5..98c2235a1c 100644
--- a/internal/coremsgs/en_struct_descriptions.go
+++ b/internal/coremsgs/en_struct_descriptions.go
@@ -319,8 +319,8 @@ var (
// ContractListenerOptions field descriptions
ContractListenerOptionsFirstEvent = ffm("ContractListenerOptions.firstEvent", "A blockchain specific string, such as a block number, to start listening from. The special strings 'oldest' and 'newest' are supported by all blockchain connectors. Default is 'newest'")
- ListenerFilterInterface = ffm("ListenerFilter.interface", "A reference to an existing FFI, containing pre-registered type information for the event")
- ListenerFilterEvent = ffm("ListenerFilter.event", "The definition of the event, either provided in-line when creating the listener, or extracted from the referenced FFI")
+ ListenerFilterInterface = ffm("ListenerFilter.interface", "A reference to an existing FFI, containing pre-registered type information for the event, used in combination with eventPath")
+ ListenerFilterEvent = ffm("ListenerFilter.event", "The definition of the event, either provided in-line when creating the listener, or extracted from the referenced FFI when supplied")
ListenerFilterEventPath = ffm("ListenerFilter.eventPath", "When creating a listener from an existing FFI, this is the pathname of the event on that FFI to be detected by this listener")
ListenerFilterLocation = ffm("ListenerFilter.location", "A blockchain specific contract identifier. For example an Ethereum contract address, or a Fabric chaincode name and channel")
ListenerFilterSignature = ffm("ListenerFilter.signature", "The stringified signature of the event and location, as computed by the blockchain plugin")
diff --git a/internal/database/sqlcommon/chart_sql.go b/internal/database/sqlcommon/chart_sql.go
index b207020be1..86d7fb27f0 100644
--- a/internal/database/sqlcommon/chart_sql.go
+++ b/internal/database/sqlcommon/chart_sql.go
@@ -60,7 +60,7 @@ func (s *SQLCommon) getSelectStatements(ns string, tableName string, intervals [
sq.Eq{"namespace": ns},
}).
OrderBy(timestampKey).
- Limit(uint64(config.GetInt(coreconfig.HistogramsMaxChartRows))))
+ Limit(config.GetUint64(coreconfig.HistogramsMaxChartRows)))
}
return queries
diff --git a/internal/database/sqlcommon/event_sql_test.go b/internal/database/sqlcommon/event_sql_test.go
index 17a95f0add..06d74a0c7d 100644
--- a/internal/database/sqlcommon/event_sql_test.go
+++ b/internal/database/sqlcommon/event_sql_test.go
@@ -107,7 +107,7 @@ func TestGetEventsInSequenceRangeE2EWithDB(t *testing.T) {
Type: core.EventTypeMessageConfirmed,
Reference: fftypes.NewUUID(),
Correlator: fftypes.NewUUID(),
- Topic: fmt.Sprintf("topic%d", i % 2),
+ Topic: fmt.Sprintf("topic%d", i%2),
Created: fftypes.Now(),
}
err := s.InsertEvent(ctx, event)
@@ -322,10 +322,9 @@ func TestGetEventsInSequenceRangeBuildQueryFail(t *testing.T) {
func TestGetEventsInSequenceRangeShouldCallGetEventsWhenNoSequencedProvidedAndThrowAnError(t *testing.T) {
s, mock := newMockProvider().init()
- mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"id", }).AddRow("only one"))
+ mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow("only one"))
f := database.EventQueryFactory.NewFilter(context.Background()).And()
_, _, err := s.GetEventsInSequenceRange(context.Background(), "ns1", f, -1, -1)
assert.NotNil(t, err)
assert.NoError(t, mock.ExpectationsWereMet())
}
-
diff --git a/internal/database/sqlcommon/provider_sqlitego_test.go b/internal/database/sqlcommon/provider_sqlitego_test.go
index 78fee5016c..24a5014762 100644
--- a/internal/database/sqlcommon/provider_sqlitego_test.go
+++ b/internal/database/sqlcommon/provider_sqlitego_test.go
@@ -46,7 +46,7 @@ type sqliteGoTestProvider struct {
capabilities *database.Capabilities
}
-// newTestProvider creates a real in-memory database provider for e2e testing
+// newSQLiteTestProvider creates a real in-memory database provider for e2e testing
func newSQLiteTestProvider(t *testing.T) (*sqliteGoTestProvider, func()) {
conf := config.RootSection("unittest.db")
conf.AddKnownKey("url", "test")
diff --git a/internal/database/sqlcommon/subscription_sql_test.go b/internal/database/sqlcommon/subscription_sql_test.go
index 30a0802754..b7bf305ac6 100644
--- a/internal/database/sqlcommon/subscription_sql_test.go
+++ b/internal/database/sqlcommon/subscription_sql_test.go
@@ -62,7 +62,7 @@ func TestSubscriptionsE2EWithDB(t *testing.T) {
// Update the subscription (this is testing what's possible at the database layer,
// and does not account for the verification that happens at the higher level)
newest := core.SubOptsFirstEventNewest
- fifty := uint16(50)
+ fifty := uint(50)
subOpts := core.SubscriptionOptions{
SubscriptionCoreOptions: core.SubscriptionCoreOptions{
FirstEvent: &newest,
diff --git a/internal/dataexchange/ffdx/dxevent.go b/internal/dataexchange/ffdx/dxevent.go
index 3043d05950..372e673183 100644
--- a/internal/dataexchange/ffdx/dxevent.go
+++ b/internal/dataexchange/ffdx/dxevent.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2023 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -90,13 +90,15 @@ func (h *FFDX) dispatchEvent(msg *wsEvent) {
switch msg.Type {
case messageFailed:
- h.callbacks.OperationUpdate(h.ctx, &core.OperationUpdate{
- Plugin: h.Name(),
- NamespacedOpID: msg.RequestID,
- Status: core.OpStatusFailed,
- ErrorMessage: msg.Error,
- Output: msg.Info,
- OnComplete: e.Ack,
+ h.callbacks.OperationUpdate(h.ctx, &core.OperationUpdateAsync{
+ OperationUpdate: core.OperationUpdate{
+ Plugin: h.Name(),
+ NamespacedOpID: msg.RequestID,
+ Status: core.OpStatusFailed,
+ ErrorMessage: msg.Error,
+ Output: msg.Info,
+ },
+ OnComplete: e.Ack,
})
return
case messageDelivered:
@@ -104,33 +106,39 @@ func (h *FFDX) dispatchEvent(msg *wsEvent) {
if h.capabilities.Manifest {
status = core.OpStatusPending
}
- h.callbacks.OperationUpdate(h.ctx, &core.OperationUpdate{
- Plugin: h.Name(),
- NamespacedOpID: msg.RequestID,
- Status: status,
- Output: msg.Info,
- OnComplete: e.Ack,
+ h.callbacks.OperationUpdate(h.ctx, &core.OperationUpdateAsync{
+ OperationUpdate: core.OperationUpdate{
+ Plugin: h.Name(),
+ NamespacedOpID: msg.RequestID,
+ Status: status,
+ Output: msg.Info,
+ },
+ OnComplete: e.Ack,
})
return
case messageAcknowledged:
- h.callbacks.OperationUpdate(h.ctx, &core.OperationUpdate{
- Plugin: h.Name(),
- NamespacedOpID: msg.RequestID,
- Status: core.OpStatusSucceeded,
- VerifyManifest: h.capabilities.Manifest,
- DXManifest: msg.Manifest,
- Output: msg.Info,
- OnComplete: e.Ack,
+ h.callbacks.OperationUpdate(h.ctx, &core.OperationUpdateAsync{
+ OperationUpdate: core.OperationUpdate{
+ Plugin: h.Name(),
+ NamespacedOpID: msg.RequestID,
+ Status: core.OpStatusSucceeded,
+ VerifyManifest: h.capabilities.Manifest,
+ DXManifest: msg.Manifest,
+ Output: msg.Info,
+ },
+ OnComplete: e.Ack,
})
return
case blobFailed:
- h.callbacks.OperationUpdate(h.ctx, &core.OperationUpdate{
- Plugin: h.Name(),
- NamespacedOpID: msg.RequestID,
- Status: core.OpStatusFailed,
- ErrorMessage: msg.Error,
- Output: msg.Info,
- OnComplete: e.Ack,
+ h.callbacks.OperationUpdate(h.ctx, &core.OperationUpdateAsync{
+ OperationUpdate: core.OperationUpdate{
+ Plugin: h.Name(),
+ NamespacedOpID: msg.RequestID,
+ Status: core.OpStatusFailed,
+ ErrorMessage: msg.Error,
+ Output: msg.Info,
+ },
+ OnComplete: e.Ack,
})
return
case blobDelivered:
@@ -138,23 +146,27 @@ func (h *FFDX) dispatchEvent(msg *wsEvent) {
if h.capabilities.Manifest {
status = core.OpStatusPending
}
- h.callbacks.OperationUpdate(h.ctx, &core.OperationUpdate{
- Plugin: h.Name(),
- NamespacedOpID: msg.RequestID,
- Status: status,
- Output: msg.Info,
- OnComplete: e.Ack,
+ h.callbacks.OperationUpdate(h.ctx, &core.OperationUpdateAsync{
+ OperationUpdate: core.OperationUpdate{
+ Plugin: h.Name(),
+ NamespacedOpID: msg.RequestID,
+ Status: status,
+ Output: msg.Info,
+ },
+ OnComplete: e.Ack,
})
return
case blobAcknowledged:
- h.callbacks.OperationUpdate(h.ctx, &core.OperationUpdate{
- Plugin: h.Name(),
- NamespacedOpID: msg.RequestID,
- Status: core.OpStatusSucceeded,
- Output: msg.Info,
- VerifyManifest: h.capabilities.Manifest,
- DXHash: msg.Hash,
- OnComplete: e.Ack,
+ h.callbacks.OperationUpdate(h.ctx, &core.OperationUpdateAsync{
+ OperationUpdate: core.OperationUpdate{
+ Plugin: h.Name(),
+ NamespacedOpID: msg.RequestID,
+ Status: core.OpStatusSucceeded,
+ Output: msg.Info,
+ VerifyManifest: h.capabilities.Manifest,
+ DXHash: msg.Hash,
+ },
+ OnComplete: e.Ack,
})
return
diff --git a/internal/dataexchange/ffdx/ffdx.go b/internal/dataexchange/ffdx/ffdx.go
index 00c63dd53a..0000083008 100644
--- a/internal/dataexchange/ffdx/ffdx.go
+++ b/internal/dataexchange/ffdx/ffdx.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2024 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -18,11 +18,17 @@ package ffdx
import (
"context"
+ "crypto/x509"
"encoding/json"
+ "encoding/pem"
+ "errors"
"fmt"
"io"
"strings"
"sync"
+ "time"
+
+ "github.com/hyperledger/firefly/internal/metrics"
"github.com/go-resty/resty/v2"
"github.com/hyperledger/firefly-common/pkg/config"
@@ -54,6 +60,8 @@ type FFDX struct {
retry *retry.Retry
backgroundStart bool
backgroundRetry *retry.Retry
+
+ metrics metrics.Manager // optional
}
type dxNode struct {
@@ -68,7 +76,7 @@ type callbacks struct {
opHandlers map[string]core.OperationCallbacks
}
-func (cb *callbacks) OperationUpdate(ctx context.Context, update *core.OperationUpdate) {
+func (cb *callbacks) OperationUpdate(ctx context.Context, update *core.OperationUpdateAsync) {
namespace, _, _ := core.ParseNamespacedOpID(ctx, update.NamespacedOpID)
if handler, ok := cb.opHandlers[namespace]; ok {
handler.OperationUpdate(update)
@@ -168,7 +176,7 @@ func (h *FFDX) Name() string {
return "ffdx"
}
-func (h *FFDX) Init(ctx context.Context, cancelCtx context.CancelFunc, config config.Section) (err error) {
+func (h *FFDX) Init(ctx context.Context, cancelCtx context.CancelFunc, config config.Section, metrics metrics.Manager) (err error) {
h.ctx = log.WithLogField(ctx, "dx", "https")
h.cancelCtx = cancelCtx
h.ackChannel = make(chan *ack)
@@ -179,6 +187,7 @@ func (h *FFDX) Init(ctx context.Context, cancelCtx context.CancelFunc, config co
}
h.needsInit = config.GetBool(DataExchangeInitEnabled)
h.nodes = make(map[string]*dxNode)
+ h.metrics = metrics
if config.GetString(ffresty.HTTPConfigURL) == "" {
return i18n.NewError(ctx, coremsgs.MsgMissingPluginConfig, "url", "dataexchange.ffdx")
@@ -295,7 +304,13 @@ func (h *FFDX) beforeConnect(ctx context.Context, w wsclient.WSClient) error {
return fmt.Errorf("DX returned non-ready status: %s", status.Status)
}
}
+
h.initialized = true
+
+ for _, cb := range h.callbacks.handlers {
+ cb.DXConnect(h)
+ }
+
return nil
}
@@ -448,6 +463,91 @@ func (h *FFDX) TransferBlob(ctx context.Context, nsOpID string, peer, sender fft
return nil
}
+func (h *FFDX) CheckNodeIdentityStatus(ctx context.Context, node *core.Identity) error {
+ if node == nil {
+ return i18n.NewError(ctx, coremsgs.MsgNodeNotProvidedForCheck)
+ }
+
+ var mismatchState = metrics.NodeIdentityDXCertMismatchStatusUnknown
+ defer func() {
+ if h.metrics != nil && h.metrics.IsMetricsEnabled() {
+ h.metrics.NodeIdentityDXCertMismatch(node.Namespace, mismatchState)
+ }
+ log.L(ctx).Debugf("Identity status checked against DX node='%s' mismatch_state='%s'", node.Name, mismatchState)
+ }()
+
+ dxPeer, err := h.GetEndpointInfo(ctx, node.Name) // should be the same as the local node
+ if err != nil {
+ return err
+ }
+
+ dxPeerCert := dxPeer.GetString("cert")
+ // if this occurs, it is either a misconfigured / broken DX or likely a DX that is compatible from an API perspective
+ // but does not have the same peer info as the HTTPS mTLS DX
+ if dxPeerCert == "" {
+ log.L(ctx).Debugf("DX peer does not have a 'cert', DX plugin may be unsupported")
+ return nil
+ }
+
+ expiry, err := extractSoonestExpiryFromCertBundle(strings.ReplaceAll(dxPeerCert, `\n`, "\n"))
+ if err == nil {
+ if expiry.Before(time.Now()) {
+ log.L(ctx).Warnf("DX certificate for node '%s' has expired", node.Name)
+ }
+
+ if h.metrics != nil && h.metrics.IsMetricsEnabled() {
+ h.metrics.NodeIdentityDXCertExpiry(node.Namespace, expiry)
+ }
+ } else {
+ log.L(ctx).Errorf("Failed to find x509 cert within DX cert bundle node='%s' namespace='%s'", node.Name, node.Namespace)
+ }
+
+ if node.Profile == nil {
+ return i18n.NewError(ctx, coremsgs.MsgNodeNotProvidedForCheck)
+ }
+
+ nodeCert := node.Profile.GetString("cert")
+ if nodeCert != "" {
+ mismatchState = metrics.NodeIdentityDXCertMismatchStatusHealthy
+ if dxPeerCert != nodeCert {
+ log.L(ctx).Warnf("DX certificate for node '%s' is out-of-sync with on-chain identity", node.Name)
+ mismatchState = metrics.NodeIdentityDXCertMismatchStatusMismatched
+ }
+ }
+
+ return nil
+}
+
+// We assume the cert with the soonest expiry is the leaf cert, but even if its the CA,
+// that's what will invalidate the leaf anyways, so really we only care about the soonest expiry.
+// So we loop through the bundle finding the soonest expiry, not necessarily the leaf.
+func extractSoonestExpiryFromCertBundle(certBundle string) (time.Time, error) {
+ var expiringCert *x509.Certificate
+ var block *pem.Block
+ var rest = []byte(certBundle)
+
+ for {
+ block, rest = pem.Decode(rest)
+ if block == nil {
+ break
+ }
+
+ cert, err := x509.ParseCertificate(block.Bytes)
+ if err != nil {
+ return time.Time{}, fmt.Errorf("failed to parse non-certificate within bundle: %v", err)
+ }
+ if expiringCert == nil || cert.NotAfter.Before(expiringCert.NotAfter) {
+ expiringCert = cert
+ }
+ }
+
+ if expiringCert == nil {
+ return time.Time{}, errors.New("no valid certificate found")
+ }
+
+ return expiringCert.NotAfter.UTC(), nil
+}
+
func (h *FFDX) ackLoop() {
for {
select {
diff --git a/internal/dataexchange/ffdx/ffdx_test.go b/internal/dataexchange/ffdx/ffdx_test.go
index 63efbcd8d0..52bcecb7ae 100644
--- a/internal/dataexchange/ffdx/ffdx_test.go
+++ b/internal/dataexchange/ffdx/ffdx_test.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2021 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -20,11 +20,18 @@ import (
"bytes"
"context"
"encoding/json"
+ "errors"
"fmt"
"io/ioutil"
"net/http"
"net/url"
+ "strings"
"testing"
+ "time"
+
+ "github.com/hyperledger/firefly/internal/metrics"
+
+ "github.com/hyperledger/firefly/mocks/metricsmocks"
"github.com/hyperledger/firefly-common/pkg/config"
"github.com/hyperledger/firefly-common/pkg/ffresty"
@@ -45,6 +52,106 @@ import (
var utConfig = config.RootSection("ffdx_unit_tests")
+const (
+ // NOTE: the CA cert expires on Monday, February 28, 2035 7:30:57 PM UTC,
+ // and the leaf cert expires on Monday, February 28, 2028 7:30:57 PM UTC
+ testCertBundle = `
+-----BEGIN CERTIFICATE-----
+MIIDqTCCApGgAwIBAgIUbZT+Ds4f2oDmGpgVi+SaQq9gxvcwDQYJKoZIhvcNAQEL
+BQAwZDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM
+DVNhbiBGcmFuY2lzY28xEzARBgNVBAoMCkV4YW1wbGUgQ0ExEzARBgNVBAMMCmV4
+YW1wbGUtY2EwHhcNMjUwMjI4MTkzMDM4WhcNMzUwMjI2MTkzMDM4WjBkMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5j
+aXNjbzETMBEGA1UECgwKRXhhbXBsZSBDQTETMBEGA1UEAwwKZXhhbXBsZS1jYTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOWBryFqk0YqQ6pzGJvBDjbV
+4BnkMzsv+Fq869Xks09OP4eW44oqfFUmpCFyS3fEmRCz+389t4mKvxcCRIJMW0f5
+K9jffG1QKUKL4UuNfEPFpM0MXTwhI+dCdvofdelzc+KBGA6CDYlnWYcCKFSuWeSu
+xrb/qCEvhcCaSYt3e2WcRHRuK+OLzM3REeJctC4G/pq858OUV5CZU2B6aGV/9uFL
+ZW3TCrOaj+Khzzt5FNvjVdLiUw0FS8VESxFA4kH8p+XUshs9S0e7LfIBSID2NU8+
++5D6HliqNqikbsny1Ps6GhLa+nI37LOVj7nFcG7uk+gb6HUN1+0YvjOJ0/zvnLEC
+AwEAAaNTMFEwHQYDVR0OBBYEFJfNoXmIn5S6W7Lcj5G/huW5q1YQMB8GA1UdIwQY
+MBaAFJfNoXmIn5S6W7Lcj5G/huW5q1YQMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBALsdRYJHQMkhjLcrO4Yha1KXh2d+irmi8AqQqQgbLIsSzuqG
+bKFiYnJ8PKHaISHlev2xRM9kEjDZ/9q8T4aUELg4eBjj7VK+gs+gSBO6peJ+AcEg
+TepsE5GHmhoIIiE/3dIP6XnaM6NBb8q0ewsIg1c5vLlrt8W96LY6Og7f+742VvoV
+H31srpGjy7c5nYjBTn/Bu84eb5Lxfvy10sJjnenkXDJvzkUcnfbRzDQ9k5ZuPa05
+x+BsxonN0iaeZH91F+Y3kgJidLnU5EhIB/1KXYjuEbl9qUxD6GFHRststPRPeOmj
+7C+BtJCIjjavysSqVMvQWLQ6rXms3SpRPAimWqM=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDqjCCApKgAwIBAgIUWnobAQ4vq8gWBAXZBf7XZG3oSiUwDQYJKoZIhvcNAQEL
+BQAwZDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM
+DVNhbiBGcmFuY2lzY28xEzARBgNVBAoMCkV4YW1wbGUgQ0ExEzARBgNVBAMMCmV4
+YW1wbGUtY2EwHhcNMjUwMjI4MTkzMDU3WhcNMjgwMjI4MTkzMDU3WjB2MQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5j
+aXNjbzEcMBoGA1UECgwTSHlwZXJsZWRnZXIgRmlyZWZseTEcMBoGA1UEAwwTaHlw
+ZXJsZWRnZXItZmlyZWZseTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AKlbQ+7cWWS0+QPp03PrdxsnAAtG2tWOk2CEG7HS3AlBU82YImhCidKOw+jQPS68
+2f2d0tYBhugqB2Ki6HsfYMGTjHDLbUQ5y+cLk6PFbvhjm39Ayd+WGmhWht5qFtRN
+gllTa/SbG8+iGaSPIVFCyvg1IzxsFnBGn+05Gu+KjpL4i0l1RqDmy5ItxKGP77in
+RPEUkejiUozg/X3v2TWAGagIVF5+EQ2Cswot9W1faAvyu/QmSGLLfSH22GdEDHXa
+U4DV5ArJ2U2eNkOuasSWGKBopa/Wh1SZjKrNsy5Gw84ihAI4k7ARoP+vu1dIPdaX
+ElipmGMtUWu0Azn2l9QJZpMCAwEAAaNCMEAwHQYDVR0OBBYEFL798jEmX2+hw70t
+SmfJA78PZnnHMB8GA1UdIwQYMBaAFJfNoXmIn5S6W7Lcj5G/huW5q1YQMA0GCSqG
+SIb3DQEBCwUAA4IBAQBY1NXTuQJZvjip33dRXyWP6GsSDKbXTSCcSF38P4/m+pcH
+r/q/upo+K+8eTtPqUwBsIywH5bypWqoIPtM+rkd3FVBe7uti2FExufpcOruzEGsY
+rNTfiFZbc7eHmFRTkKXWW4j6b6ElygrBvV999BhCRNf6NS0/syjqsbALHkFGeIcl
+78wdaR+m2XVJBV7SmPmZ/EQzxvhCZONNVyU5zvW2sehI7sRbZt9/FG5U1Ng0LarW
+R0gnXX/IZFnLhLh6UpLOBB0KIGENh75EEU7755jMKDKFj16D0uA1Lzrh5YxicTMy
+ydFYQLpLycsWl2oV3JB4pO5TIzjY9awkRE0MeMMc
+-----END CERTIFICATE-----
+`
+ // The CA is at the bottom of the bundle and expires same as above,
+ // Monday, February 28, 2035 7:30:57 PM. The leaf cert at the top of
+ // the bundle is already expired.
+ testExpiredCert = `
+-----BEGIN CERTIFICATE-----
+MIIDqjCCApKgAwIBAgIUWnobAQ4vq8gWBAXZBf7XZG3oSicwDQYJKoZIhvcNAQEL
+BQAwZDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM
+DVNhbiBGcmFuY2lzY28xEzARBgNVBAoMCkV4YW1wbGUgQ0ExEzARBgNVBAMMCmV4
+YW1wbGUtY2EwHhcNMjUwMzAyMTQxNDA1WhcNMjUwMzAyMTQxNDA1WjB2MQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5j
+aXNjbzEcMBoGA1UECgwTSHlwZXJsZWRnZXIgRmlyZWZseTEcMBoGA1UEAwwTaHlw
+ZXJsZWRnZXItZmlyZWZseTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AKlbQ+7cWWS0+QPp03PrdxsnAAtG2tWOk2CEG7HS3AlBU82YImhCidKOw+jQPS68
+2f2d0tYBhugqB2Ki6HsfYMGTjHDLbUQ5y+cLk6PFbvhjm39Ayd+WGmhWht5qFtRN
+gllTa/SbG8+iGaSPIVFCyvg1IzxsFnBGn+05Gu+KjpL4i0l1RqDmy5ItxKGP77in
+RPEUkejiUozg/X3v2TWAGagIVF5+EQ2Cswot9W1faAvyu/QmSGLLfSH22GdEDHXa
+U4DV5ArJ2U2eNkOuasSWGKBopa/Wh1SZjKrNsy5Gw84ihAI4k7ARoP+vu1dIPdaX
+ElipmGMtUWu0Azn2l9QJZpMCAwEAAaNCMEAwHQYDVR0OBBYEFL798jEmX2+hw70t
+SmfJA78PZnnHMB8GA1UdIwQYMBaAFJfNoXmIn5S6W7Lcj5G/huW5q1YQMA0GCSqG
+SIb3DQEBCwUAA4IBAQA1dY8UCf1YSLG3Vu/u20ucw5q9tnYYoTi4fHm/g+imTvEQ
+KgTQBd5s9EHmj0BSjVFy9eSSTx5XiH6JqzGhCJRSbOIQ8RwrXpUlTuLr7gp0cO9c
+Ykxz6wt0k1F+9Iq+K8Eb6jzXoZe/ebMz611zUqY7+9lIl1AIIgx96MoZcDS/LA0e
+p/TUQ6q+Mg3W9pSXqLm8jmWNBfDViQF1v9Z3ASFYHUF/yak8jMdBEUpAqDadd/ay
+BHm9m8IvFevQjpUw6kyyg77ehEBBn7H/ISTL3HTCpUbkR3qUnFjOyBJ0G02XoozB
+I/hI0mpd6y+/JwyvG0smbD2lioiO/JQaUEZGU8pU
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDqTCCApGgAwIBAgIUbZT+Ds4f2oDmGpgVi+SaQq9gxvcwDQYJKoZIhvcNAQEL
+BQAwZDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM
+DVNhbiBGcmFuY2lzY28xEzARBgNVBAoMCkV4YW1wbGUgQ0ExEzARBgNVBAMMCmV4
+YW1wbGUtY2EwHhcNMjUwMjI4MTkzMDM4WhcNMzUwMjI2MTkzMDM4WjBkMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5j
+aXNjbzETMBEGA1UECgwKRXhhbXBsZSBDQTETMBEGA1UEAwwKZXhhbXBsZS1jYTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOWBryFqk0YqQ6pzGJvBDjbV
+4BnkMzsv+Fq869Xks09OP4eW44oqfFUmpCFyS3fEmRCz+389t4mKvxcCRIJMW0f5
+K9jffG1QKUKL4UuNfEPFpM0MXTwhI+dCdvofdelzc+KBGA6CDYlnWYcCKFSuWeSu
+xrb/qCEvhcCaSYt3e2WcRHRuK+OLzM3REeJctC4G/pq858OUV5CZU2B6aGV/9uFL
+ZW3TCrOaj+Khzzt5FNvjVdLiUw0FS8VESxFA4kH8p+XUshs9S0e7LfIBSID2NU8+
++5D6HliqNqikbsny1Ps6GhLa+nI37LOVj7nFcG7uk+gb6HUN1+0YvjOJ0/zvnLEC
+AwEAAaNTMFEwHQYDVR0OBBYEFJfNoXmIn5S6W7Lcj5G/huW5q1YQMB8GA1UdIwQY
+MBaAFJfNoXmIn5S6W7Lcj5G/huW5q1YQMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBALsdRYJHQMkhjLcrO4Yha1KXh2d+irmi8AqQqQgbLIsSzuqG
+bKFiYnJ8PKHaISHlev2xRM9kEjDZ/9q8T4aUELg4eBjj7VK+gs+gSBO6peJ+AcEg
+TepsE5GHmhoIIiE/3dIP6XnaM6NBb8q0ewsIg1c5vLlrt8W96LY6Og7f+742VvoV
+H31srpGjy7c5nYjBTn/Bu84eb5Lxfvy10sJjnenkXDJvzkUcnfbRzDQ9k5ZuPa05
+x+BsxonN0iaeZH91F+Y3kgJidLnU5EhIB/1KXYjuEbl9qUxD6GFHRststPRPeOmj
+7C+BtJCIjjavysSqVMvQWLQ6rXms3SpRPAimWqM=
+-----END CERTIFICATE-----
+`
+)
+
func newTestFFDX(t *testing.T, manifestEnabled bool) (h *FFDX, toServer, fromServer chan string, httpURL string, done func()) {
mockedClient := &http.Client{}
httpmock.ActivateNonDefault(mockedClient)
@@ -64,8 +171,9 @@ func newTestFFDX(t *testing.T, manifestEnabled bool) (h *FFDX, toServer, fromSer
h = &FFDX{initialized: true}
h.InitConfig(utConfig)
+ mmm := metricsmocks.NewManager(t)
dxCtx, dxCancel := context.WithCancel(context.Background())
- err := h.Init(dxCtx, dxCancel, utConfig)
+ err := h.Init(dxCtx, dxCancel, utConfig, mmm)
assert.NoError(t, err)
assert.Equal(t, "ffdx", h.Name())
assert.NotNil(t, h.Capabilities())
@@ -114,7 +222,7 @@ func TestInitBadURL(t *testing.T) {
h.InitConfig(utConfig)
utConfig.Set(ffresty.HTTPConfigURL, "::::////")
ctx, cancel := context.WithCancel(context.Background())
- err := h.Init(ctx, cancel, utConfig)
+ err := h.Init(ctx, cancel, utConfig, nil)
assert.Regexp(t, "FF00149", err)
}
@@ -127,7 +235,7 @@ func TestInitBadTLS(t *testing.T) {
tlsConfig.Set(fftls.HTTPConfTLSEnabled, true)
tlsConfig.Set(fftls.HTTPConfTLSCAFile, "badCA")
ctx, cancel := context.WithCancel(context.Background())
- err := h.Init(ctx, cancel, utConfig)
+ err := h.Init(ctx, cancel, utConfig, nil)
assert.Regexp(t, "FF00153", err)
}
@@ -136,13 +244,13 @@ func TestInitMissingURL(t *testing.T) {
h := &FFDX{}
h.InitConfig(utConfig)
ctx, cancel := context.WithCancel(context.Background())
- err := h.Init(ctx, cancel, utConfig)
+ err := h.Init(ctx, cancel, utConfig, nil)
assert.Regexp(t, "FF10138", err)
}
func opAcker() func(args mock.Arguments) {
return func(args mock.Arguments) {
- args[0].(*core.OperationUpdate).OnComplete()
+ args[0].(*core.OperationUpdateAsync).OnComplete()
}
}
@@ -159,7 +267,7 @@ func TestInitWithBackgroundStart(t *testing.T) {
h.InitConfig(utConfig)
ctx, cancel := context.WithCancel(context.Background())
- err := h.Init(ctx, cancel, utConfig)
+ err := h.Init(ctx, cancel, utConfig, nil)
assert.NoError(t, err)
assert.NotNil(t, h.backgroundRetry)
@@ -453,7 +561,7 @@ func TestBackgroundStartWSFail(t *testing.T) {
dxCtx, dxCancel := context.WithCancel(context.Background())
defer dxCancel()
- err := h.Init(dxCtx, dxCancel, utConfig)
+ err := h.Init(dxCtx, dxCancel, utConfig, nil)
assert.NoError(t, err)
assert.Equal(t, "ffdx", h.Name())
assert.NotNil(t, h.Capabilities())
@@ -480,7 +588,7 @@ func TestMessageEventsBackgroundStart(t *testing.T) {
// Starting in background mode and making sure the event loop are started as well
// to listen to messages
utConfig.Set(DataExchangeBackgroundStart, true)
- h.Init(h.ctx, h.cancelCtx, utConfig)
+ h.Init(h.ctx, h.cancelCtx, utConfig, nil)
mcb := &dataexchangemocks.Callbacks{}
h.SetHandler("ns1", "node1", mcb)
@@ -488,11 +596,13 @@ func TestMessageEventsBackgroundStart(t *testing.T) {
h.SetOperationHandler("ns1", ocb)
h.AddNode(context.Background(), "ns1", "node1", fftypes.JSONObject{"id": "peer1"})
+ mcb.On("DXConnect", h).Return(nil)
+
err := h.Start()
assert.NoError(t, err)
namespacedID1 := fmt.Sprintf("ns1:%s", fftypes.NewUUID())
- ocb.On("OperationUpdate", mock.MatchedBy(func(ev *core.OperationUpdate) bool {
+ ocb.On("OperationUpdate", mock.MatchedBy(func(ev *core.OperationUpdateAsync) bool {
return ev.NamespacedOpID == namespacedID1 &&
ev.Status == core.OpStatusFailed &&
ev.ErrorMessage == "pop" &&
@@ -503,7 +613,7 @@ func TestMessageEventsBackgroundStart(t *testing.T) {
assert.Equal(t, `{"action":"ack","id":"1"}`, string(msg))
namespacedID2 := fmt.Sprintf("ns1:%s", fftypes.NewUUID())
- ocb.On("OperationUpdate", mock.MatchedBy(func(ev *core.OperationUpdate) bool {
+ ocb.On("OperationUpdate", mock.MatchedBy(func(ev *core.OperationUpdateAsync) bool {
return ev.NamespacedOpID == namespacedID2 &&
ev.Status == core.OpStatusSucceeded &&
ev.Plugin == "ffdx"
@@ -513,7 +623,7 @@ func TestMessageEventsBackgroundStart(t *testing.T) {
assert.Equal(t, `{"action":"ack","id":"2"}`, string(msg))
namespacedID3 := fmt.Sprintf("ns1:%s", fftypes.NewUUID())
- ocb.On("OperationUpdate", mock.MatchedBy(func(ev *core.OperationUpdate) bool {
+ ocb.On("OperationUpdate", mock.MatchedBy(func(ev *core.OperationUpdateAsync) bool {
return ev.NamespacedOpID == namespacedID3 &&
ev.Status == core.OpStatusSucceeded &&
ev.DXManifest == `{"manifest":true}` &&
@@ -547,12 +657,13 @@ func TestMessageEvents(t *testing.T) {
ocb := &coremocks.OperationCallbacks{}
h.SetOperationHandler("ns1", ocb)
h.AddNode(context.Background(), "ns1", "node1", fftypes.JSONObject{"id": "peer1"})
+ mcb.On("DXConnect", h).Return(nil)
err := h.Start()
assert.NoError(t, err)
namespacedID1 := fmt.Sprintf("ns1:%s", fftypes.NewUUID())
- ocb.On("OperationUpdate", mock.MatchedBy(func(ev *core.OperationUpdate) bool {
+ ocb.On("OperationUpdate", mock.MatchedBy(func(ev *core.OperationUpdateAsync) bool {
return ev.NamespacedOpID == namespacedID1 &&
ev.Status == core.OpStatusFailed &&
ev.ErrorMessage == "pop" &&
@@ -563,7 +674,7 @@ func TestMessageEvents(t *testing.T) {
assert.Equal(t, `{"action":"ack","id":"1"}`, string(msg))
namespacedID2 := fmt.Sprintf("ns1:%s", fftypes.NewUUID())
- ocb.On("OperationUpdate", mock.MatchedBy(func(ev *core.OperationUpdate) bool {
+ ocb.On("OperationUpdate", mock.MatchedBy(func(ev *core.OperationUpdateAsync) bool {
return ev.NamespacedOpID == namespacedID2 &&
ev.Status == core.OpStatusSucceeded &&
ev.Plugin == "ffdx"
@@ -573,7 +684,7 @@ func TestMessageEvents(t *testing.T) {
assert.Equal(t, `{"action":"ack","id":"2"}`, string(msg))
namespacedID3 := fmt.Sprintf("ns1:%s", fftypes.NewUUID())
- ocb.On("OperationUpdate", mock.MatchedBy(func(ev *core.OperationUpdate) bool {
+ ocb.On("OperationUpdate", mock.MatchedBy(func(ev *core.OperationUpdateAsync) bool {
return ev.NamespacedOpID == namespacedID3 &&
ev.Status == core.OpStatusSucceeded &&
ev.DXManifest == `{"manifest":true}` &&
@@ -612,12 +723,13 @@ func TestBlobEvents(t *testing.T) {
ocb := &coremocks.OperationCallbacks{}
h.SetOperationHandler("ns1", ocb)
h.AddNode(context.Background(), "ns1", "node1", fftypes.JSONObject{"id": "peer1"})
+ mcb.On("DXConnect", h).Return(nil)
err := h.Start()
assert.NoError(t, err)
namespacedID5 := fmt.Sprintf("ns1:%s", fftypes.NewUUID())
- ocb.On("OperationUpdate", mock.MatchedBy(func(ev *core.OperationUpdate) bool {
+ ocb.On("OperationUpdate", mock.MatchedBy(func(ev *core.OperationUpdateAsync) bool {
return ev.NamespacedOpID == namespacedID5 &&
ev.Status == core.OpStatusFailed &&
ev.ErrorMessage == "pop" &&
@@ -628,7 +740,7 @@ func TestBlobEvents(t *testing.T) {
assert.Equal(t, `{"action":"ack","id":"5"}`, string(msg))
namespacedID6 := fmt.Sprintf("ns1:%s", fftypes.NewUUID())
- ocb.On("OperationUpdate", mock.MatchedBy(func(ev *core.OperationUpdate) bool {
+ ocb.On("OperationUpdate", mock.MatchedBy(func(ev *core.OperationUpdateAsync) bool {
return ev.NamespacedOpID == namespacedID6 &&
ev.Status == core.OpStatusSucceeded &&
ev.Output.String() == `{"some":"details"}` &&
@@ -650,7 +762,7 @@ func TestBlobEvents(t *testing.T) {
assert.Equal(t, `{"action":"ack","id":"9"}`, string(msg))
namespacedID10 := fmt.Sprintf("ns1:%s", fftypes.NewUUID())
- ocb.On("OperationUpdate", mock.MatchedBy(func(ev *core.OperationUpdate) bool {
+ ocb.On("OperationUpdate", mock.MatchedBy(func(ev *core.OperationUpdateAsync) bool {
return ev.NamespacedOpID == namespacedID10 &&
ev.Status == core.OpStatusSucceeded &&
ev.Output.String() == `{"signatures":"and stuff"}` &&
@@ -669,6 +781,12 @@ func TestEventsWithManifest(t *testing.T) {
h, toServer, fromServer, _, done := newTestFFDX(t, true)
defer done()
+ mcb := &dataexchangemocks.Callbacks{}
+ mcb.On("DXConnect", h).Return(nil)
+ h.SetHandler("ns1", "node1", mcb)
+ ocb := &coremocks.OperationCallbacks{}
+ h.SetOperationHandler("ns1", ocb)
+
err := h.Start()
assert.NoError(t, err)
@@ -677,13 +795,8 @@ func TestEventsWithManifest(t *testing.T) {
msg := <-toServer
assert.Equal(t, `{"action":"ack","id":"0"}`, string(msg))
- mcb := &dataexchangemocks.Callbacks{}
- h.SetHandler("ns1", "node1", mcb)
- ocb := &coremocks.OperationCallbacks{}
- h.SetOperationHandler("ns1", ocb)
-
namespacedID1 := fmt.Sprintf("ns1:%s", fftypes.NewUUID())
- ocb.On("OperationUpdate", mock.MatchedBy(func(ev *core.OperationUpdate) bool {
+ ocb.On("OperationUpdate", mock.MatchedBy(func(ev *core.OperationUpdateAsync) bool {
return ev.NamespacedOpID == namespacedID1 &&
ev.Status == core.OpStatusPending &&
ev.Plugin == "ffdx"
@@ -693,7 +806,7 @@ func TestEventsWithManifest(t *testing.T) {
assert.Equal(t, `{"action":"ack","id":"1"}`, string(msg))
namespacedID2 := fmt.Sprintf("ns1:%s", fftypes.NewUUID())
- ocb.On("OperationUpdate", mock.MatchedBy(func(ev *core.OperationUpdate) bool {
+ ocb.On("OperationUpdate", mock.MatchedBy(func(ev *core.OperationUpdateAsync) bool {
return ev.NamespacedOpID == namespacedID2 &&
ev.Status == core.OpStatusPending &&
ev.Plugin == "ffdx"
@@ -807,7 +920,7 @@ func TestWebsocketWithReinit(t *testing.T) {
h.InitConfig(utConfig)
ctx, cancel := context.WithCancel(context.Background())
- err := h.Init(ctx, cancel, utConfig)
+ err := h.Init(ctx, cancel, utConfig, nil)
assert.NoError(t, err)
h.AddNode(context.Background(), "ns1", "node1", fftypes.JSONObject{})
@@ -855,8 +968,11 @@ func TestWebsocketWithEmptyNodesInit(t *testing.T) {
h.InitConfig(utConfig)
ctx, cancel := context.WithCancel(context.Background())
- err := h.Init(ctx, cancel, utConfig)
+ err := h.Init(ctx, cancel, utConfig, nil)
assert.NoError(t, err)
+ dxc := &dataexchangemocks.Callbacks{}
+ h.callbacks = callbacks{handlers: map[string]dataexchange.Callbacks{"ns1": dxc}}
+ dxc.On("DXConnect", h).Return(nil)
err = h.Start()
assert.NoError(t, err)
@@ -905,3 +1021,244 @@ func TestDeleteBlobFail(t *testing.T) {
err := h.DeleteBlob(context.Background(), fmt.Sprintf("ns1/%s", u))
assert.Regexp(t, "FF10229", err)
}
+
+type mockDXCallbacks struct {
+ connectCalls int
+}
+
+func (m *mockDXCallbacks) DXConnect(plugin dataexchange.Plugin) {
+ m.connectCalls++
+}
+
+func (m *mockDXCallbacks) DXEvent(plugin dataexchange.Plugin, event dataexchange.DXEvent) error {
+ panic("implement me")
+}
+
+func TestWebsocketDXConnect(t *testing.T) {
+ mockedClient := &http.Client{}
+ httpmock.ActivateNonDefault(mockedClient)
+ defer httpmock.DeactivateAndReset()
+
+ _, _, wsURL, cancel := wsclient.NewTestWSServer(nil)
+ defer cancel()
+
+ u, _ := url.Parse(wsURL)
+ u.Scheme = "http"
+ httpURL := u.String()
+ h := &FFDX{}
+
+ coreconfig.Reset()
+ h.InitConfig(utConfig)
+ utConfig.Set(ffresty.HTTPConfigURL, httpURL)
+ utConfig.Set(ffresty.HTTPCustomClient, mockedClient)
+ utConfig.Set(DataExchangeInitEnabled, true)
+
+ httpmock.RegisterResponder("POST", fmt.Sprintf("%s/api/v1/init", httpURL),
+ func(req *http.Request) (*http.Response, error) {
+ var reqNodes []fftypes.JSONObject
+
+ // we want to make sure when theres are no peer nodes, an empty list is being
+ // passed as the req, not "null"
+ err := json.NewDecoder(req.Body).Decode(&reqNodes)
+ assert.NoError(t, err)
+ assert.Empty(t, reqNodes)
+ assert.NotNil(t, reqNodes)
+
+ return httpmock.NewJsonResponse(200, fftypes.JSONObject{
+ "status": "ready",
+ })
+ })
+
+ h.InitConfig(utConfig)
+ ctx, cancel := context.WithCancel(context.Background())
+ err := h.Init(ctx, cancel, utConfig, nil)
+ assert.NoError(t, err)
+ dxc := &mockDXCallbacks{
+ connectCalls: 0,
+ }
+ h.callbacks = callbacks{handlers: map[string]dataexchange.Callbacks{"ns1": dxc}}
+
+ err = h.Start()
+ assert.NoError(t, err)
+
+ assert.Equal(t, 1, httpmock.GetTotalCallCount())
+ assert.True(t, h.initialized)
+ assert.Equal(t, 1, dxc.connectCalls)
+}
+
+func TestExtractSoonestExpiryFromCertBundleEmpty(t *testing.T) {
+ _, err := extractSoonestExpiryFromCertBundle("")
+ assert.ErrorContains(t, err, "no valid certificate found")
+
+}
+
+func TestExtractSoonestExpiryFromCertBundleBadBundle(t *testing.T) {
+ nonCertPEMBundle := `
+-----BEGIN NON-CERTIFICATE-----
+MIIDXTCCAkWgAwIBAgIJALa6+u2k5u2kMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIDApxdWVlbnNsYW5kMREwDwYDVQQHDAhCcm9va2ZpZWxk
+-----END NON-CERTIFICATE-----
+`
+
+ _, err := extractSoonestExpiryFromCertBundle(nonCertPEMBundle)
+ assert.ErrorContains(t, err, "failed to parse non-certificate within bundle")
+}
+
+func TestCheckNodeIdentityStatusNodeNil(t *testing.T) {
+ mmm := metricsmocks.NewManager(t)
+ h := &FFDX{metrics: mmm}
+ err := h.CheckNodeIdentityStatus(context.Background(), nil)
+ assert.Error(t, err)
+}
+
+func TestCheckNodeIdentityStatusReturnsNilWhenCertIsEmpty(t *testing.T) {
+ h, _, _, httpURL, done := newTestFFDX(t, false)
+ defer done()
+
+ httpmock.RegisterResponder("GET", fmt.Sprintf("%s/api/v1/id", httpURL),
+ httpmock.NewJsonResponderOrPanic(200, fftypes.JSONObject{
+ "id": "peer1",
+ "endpoint": "https://peer1.example.com",
+ "cert": "",
+ }))
+
+ node := &core.Identity{
+ IdentityBase: core.IdentityBase{
+ Namespace: "ns1",
+ },
+ }
+
+ h.metrics.(*metricsmocks.Manager).On("IsMetricsEnabled").Return(true)
+ h.metrics.(*metricsmocks.Manager).On("NodeIdentityDXCertMismatch", "ns1", metrics.NodeIdentityDXCertMismatchStatusUnknown).Return(true)
+
+ err := h.CheckNodeIdentityStatus(context.Background(), node)
+ assert.NoError(t, err)
+}
+
+func TestCheckNodeIdentityStatusReturnsErrorWhenNodeProfileIsNil(t *testing.T) {
+ h, _, _, httpURL, done := newTestFFDX(t, false)
+ defer done()
+
+ httpmock.RegisterResponder("GET", fmt.Sprintf("%s/api/v1/id", httpURL),
+ httpmock.NewJsonResponderOrPanic(200, fftypes.JSONObject{
+ "id": "peer1",
+ "endpoint": "https://peer1.example.com",
+ "cert": "a-cert",
+ }))
+
+ node := &core.Identity{
+ IdentityBase: core.IdentityBase{
+ Namespace: "ns1",
+ },
+ }
+ h.metrics.(*metricsmocks.Manager).On("IsMetricsEnabled").Return(false)
+
+ err := h.CheckNodeIdentityStatus(context.Background(), node)
+ assert.Error(t, err)
+}
+
+func TestCheckNodeIdentityStatusEndpointInfoFails(t *testing.T) {
+ h, _, _, httpURL, done := newTestFFDX(t, false)
+ defer done()
+
+ httpmock.RegisterResponder("GET", fmt.Sprintf("%s/api/v1/id", httpURL),
+ httpmock.NewErrorResponder(errors.New("failed to get peer info")))
+
+ h.metrics.(*metricsmocks.Manager).On("IsMetricsEnabled").Return(true)
+ h.metrics.(*metricsmocks.Manager).On("NodeIdentityDXCertMismatch", "ns1", metrics.NodeIdentityDXCertMismatchStatusUnknown).Return(true)
+
+ node := &core.Identity{
+ IdentityBase: core.IdentityBase{
+ Namespace: "ns1",
+ },
+ }
+ err := h.CheckNodeIdentityStatus(context.Background(), node)
+ assert.Error(t, err)
+}
+
+func TestCheckNodeIdentityStatusSetsMismatchStateWhenCertsDiffer(t *testing.T) {
+ h, _, _, httpURL, done := newTestFFDX(t, false)
+ defer done()
+
+ httpmock.RegisterResponder("GET", fmt.Sprintf("%s/api/v1/id", httpURL),
+ httpmock.NewJsonResponderOrPanic(200, fftypes.JSONObject{
+ "id": "peer1",
+ "endpoint": "https://peer1.example.com",
+ "cert": "a-cert",
+ }))
+
+ node := &core.Identity{
+ IdentityBase: core.IdentityBase{
+ Namespace: "ns1",
+ },
+ IdentityProfile: core.IdentityProfile{
+ Profile: fftypes.JSONObject{"cert": "b-cert"},
+ },
+ }
+
+ h.metrics.(*metricsmocks.Manager).On("IsMetricsEnabled").Return(true)
+ h.metrics.(*metricsmocks.Manager).On("NodeIdentityDXCertMismatch", "ns1", metrics.NodeIdentityDXCertMismatchStatusMismatched).Return(true)
+ err := h.CheckNodeIdentityStatus(context.Background(), node)
+ assert.NoError(t, err)
+}
+
+func TestCheckNodeIdentityStatusSetsHealthyStateWhenCertsMatch(t *testing.T) {
+ h, _, _, httpURL, done := newTestFFDX(t, false)
+ defer done()
+
+ jsonFriendlyCert := strings.ReplaceAll(testCertBundle, "\n", `\n`)
+
+ httpmock.RegisterResponder("GET", fmt.Sprintf("%s/api/v1/id", httpURL),
+ httpmock.NewJsonResponderOrPanic(200, fftypes.JSONObject{
+ "id": "peer1",
+ "endpoint": "https://peer1.example.com",
+ "cert": jsonFriendlyCert,
+ }))
+
+ node := &core.Identity{
+ IdentityBase: core.IdentityBase{
+ Namespace: "ns1",
+ },
+ IdentityProfile: core.IdentityProfile{
+ Profile: fftypes.JSONObject{"cert": jsonFriendlyCert},
+ },
+ }
+
+ h.metrics.(*metricsmocks.Manager).On("IsMetricsEnabled").Return(true)
+ h.metrics.(*metricsmocks.Manager).On("NodeIdentityDXCertMismatch", "ns1", metrics.NodeIdentityDXCertMismatchStatusHealthy).Return(true)
+ expiry := time.Unix(1835379057, 0).UTC()
+ h.metrics.(*metricsmocks.Manager).On("NodeIdentityDXCertExpiry", "ns1", expiry).Return(true)
+
+ err := h.CheckNodeIdentityStatus(context.Background(), node)
+ assert.NoError(t, err)
+}
+
+func TestCheckNodeIdentityStatusSetsHealthyStateWhenCertsExpire(t *testing.T) {
+ h, _, _, httpURL, done := newTestFFDX(t, false)
+ defer done()
+
+ jsonFriendlyCert := strings.ReplaceAll(testExpiredCert, "\n", `\n`)
+
+ httpmock.RegisterResponder("GET", fmt.Sprintf("%s/api/v1/id", httpURL),
+ httpmock.NewJsonResponderOrPanic(200, fftypes.JSONObject{
+ "id": "peer1",
+ "endpoint": "https://peer1.example.com",
+ "cert": jsonFriendlyCert,
+ }))
+ node := &core.Identity{
+ IdentityBase: core.IdentityBase{
+ Namespace: "ns1",
+ },
+ IdentityProfile: core.IdentityProfile{
+ Profile: fftypes.JSONObject{"cert": jsonFriendlyCert},
+ },
+ }
+
+ h.metrics.(*metricsmocks.Manager).On("IsMetricsEnabled").Return(true)
+ h.metrics.(*metricsmocks.Manager).On("NodeIdentityDXCertMismatch", "ns1", metrics.NodeIdentityDXCertMismatchStatusHealthy).Return(true)
+ expiry := time.Unix(1740924845, 0).UTC()
+ h.metrics.(*metricsmocks.Manager).On("NodeIdentityDXCertExpiry", "ns1", expiry).Return(true)
+
+ err := h.CheckNodeIdentityStatus(context.Background(), node)
+ assert.NoError(t, err)
+}
diff --git a/internal/definitions/handler_identity_claim.go b/internal/definitions/handler_identity_claim.go
index 8dff1604db..fcbfa16342 100644
--- a/internal/definitions/handler_identity_claim.go
+++ b/internal/definitions/handler_identity_claim.go
@@ -246,5 +246,23 @@ func (dh *definitionHandler) handleIdentityClaim(ctx context.Context, state *cor
event := core.NewEvent(core.EventTypeIdentityConfirmed, identity.Namespace, identity.ID, nil, core.SystemTopicDefinitions)
return dh.database.InsertEvent(ctx, event)
})
+
+ if dh.multiparty && identity.Type == core.IdentityTypeNode {
+ nodeDID, err := dh.identity.GetLocalNodeDID(ctx)
+ if err != nil {
+ return HandlerResult{Action: core.ActionRetry}, err
+ }
+
+ if nodeDID == identity.DID {
+ state.AddFinalize(func(ctx context.Context) error {
+ err := dh.exchange.CheckNodeIdentityStatus(ctx, identity)
+ if err != nil {
+ log.L(ctx).Warnf("Failed to check node identity status relative to dataexchange: %s", err)
+ }
+ return nil
+ })
+ }
+ }
+
return HandlerResult{Action: core.ActionConfirm}, nil
}
diff --git a/internal/definitions/handler_identity_claim_test.go b/internal/definitions/handler_identity_claim_test.go
index 17074f044c..a042c58115 100644
--- a/internal/definitions/handler_identity_claim_test.go
+++ b/internal/definitions/handler_identity_claim_test.go
@@ -19,6 +19,7 @@ package definitions
import (
"context"
"encoding/json"
+ "errors"
"fmt"
"testing"
@@ -53,6 +54,33 @@ func testOrgIdentity(t *testing.T, name string) *core.Identity {
return i
}
+func testNodeIdentity(t *testing.T, name string, parent *core.Identity) *core.Identity {
+ i := &core.Identity{
+ IdentityBase: core.IdentityBase{
+ ID: fftypes.NewUUID(),
+ Type: core.IdentityTypeNode,
+ Namespace: "ns1",
+ Name: name,
+ Parent: parent.ID,
+ },
+ IdentityProfile: core.IdentityProfile{
+ Description: "desc",
+ Profile: fftypes.JSONObject{
+ "cert": "some cert",
+ "endpoint": "https://a-dx-endpoint",
+ "id": "dx id",
+ },
+ },
+ Messages: core.IdentityMessages{
+ Claim: fftypes.NewUUID(),
+ },
+ }
+ var err error
+ i.DID, err = i.GenerateDID(context.Background())
+ assert.NoError(t, err)
+ return i
+}
+
func testCustomIdentity(t *testing.T, name string, parent *core.Identity) *core.Identity {
i := &core.Identity{
IdentityBase: core.IdentityBase{
@@ -136,6 +164,38 @@ func testCustomClaimAndVerification(t *testing.T) (*core.Identity, *core.Identit
return custom1, org1, claimMsg, claimData, verifyMsg, verifyData
}
+func testNodeRegistrationAndVerification(t *testing.T) (*core.Identity, *core.Identity, *core.Message, *core.Data) {
+ org1 := testOrgIdentity(t, "org1")
+ node1 := testNodeIdentity(t, "node1", org1)
+
+ ic := &core.IdentityClaim{
+ Identity: node1,
+ }
+ b, err := json.Marshal(&ic)
+ assert.NoError(t, err)
+ claimData := &core.Data{
+ ID: fftypes.NewUUID(),
+ Value: fftypes.JSONAnyPtrBytes(b),
+ }
+
+ claimMsg := &core.Message{
+ Header: core.MessageHeader{
+ Namespace: "ns1",
+ ID: node1.Messages.Claim,
+ Type: core.MessageTypeDefinition,
+ Tag: core.SystemTagIdentityClaim,
+ Topics: fftypes.FFStringArray{node1.Topic()},
+ SignerRef: core.SignerRef{
+ Author: org1.DID,
+ Key: "0x12345",
+ },
+ },
+ }
+ claimMsg.Hash = fftypes.NewRandB32()
+
+ return node1, org1, claimMsg, claimData
+}
+
func TestHandleDefinitionIdentityClaimCustomWithExistingParentVerificationOk(t *testing.T) {
dh, bs := newTestDefinitionHandler(t)
defer dh.cleanup(t)
@@ -539,3 +599,76 @@ func TestHandleDefinitionIdentityClaimBadData(t *testing.T) {
bs.assertNoFinalizers()
}
+
+func TestHandleDefinitionIdentityClaimLocalNodeWithFailingStatusCheck(t *testing.T) {
+ dh, bs := newTestDefinitionHandler(t)
+ defer dh.cleanup(t)
+
+ ctx := context.Background()
+ node1, org1, claimMsg, claimData := testNodeRegistrationAndVerification(t)
+
+ dh.mim.On("VerifyIdentityChain", ctx, node1).Return(org1, false, nil)
+ dh.mdi.On("GetIdentityByName", ctx, core.IdentityTypeNode, node1.Namespace, node1.Name).Return(nil, nil)
+ dh.mdi.On("GetIdentityByID", ctx, "ns1", node1.ID).Return(nil, nil)
+ dh.mdi.On("GetVerifierByValue", ctx, core.VerifierTypeFFDXPeerID, "ns1", "a dx").Return(nil, nil)
+ dh.mdi.On("UpsertIdentity", ctx, mock.MatchedBy(func(identity *core.Identity) bool {
+ assert.Equal(t, *claimMsg.Header.ID, *identity.Messages.Claim)
+ return true
+ }), database.UpsertOptimizationNew).Return(nil)
+ dh.mdi.On("UpsertVerifier", ctx, mock.MatchedBy(func(verifier *core.Verifier) bool {
+ assert.Equal(t, core.VerifierTypeFFDXPeerID, verifier.Type)
+ assert.Equal(t, "a dx", verifier.Value)
+ assert.Equal(t, *node1.ID, *verifier.Identity)
+ return true
+ }), database.UpsertOptimizationNew).Return(nil)
+ dh.mdi.On("InsertEvent", mock.Anything, mock.MatchedBy(func(event *core.Event) bool {
+ return event.Type == core.EventTypeIdentityConfirmed
+ })).Return(nil)
+
+ dh.mdx.On("GetPeerID", node1.Profile).Return("a dx")
+ dh.mdx.On("AddNode", ctx, "ns1", node1.Name, node1.Profile).Return(nil)
+ dh.mim.On("GetLocalNodeDID", ctx).Return(node1.DID, nil)
+ dh.mdx.On("CheckNodeIdentityStatus", ctx, node1).Return(errors.New("failed to check status but no worries"))
+
+ dh.multiparty = true
+ action, err := dh.HandleDefinitionBroadcast(ctx, &bs.BatchState, claimMsg, core.DataArray{claimData}, fftypes.NewUUID())
+ assert.Equal(t, HandlerResult{Action: core.ActionConfirm}, action)
+ assert.NoError(t, err)
+ assert.Equal(t, []string{node1.DID}, bs.ConfirmedDIDClaims)
+
+ err = bs.RunPreFinalize(ctx)
+ assert.NoError(t, err)
+ err = bs.RunFinalize(ctx)
+ assert.NoError(t, err)
+}
+
+func TestHandleDefinitionIdentityClaimLocaNodeMisconfigured(t *testing.T) {
+ dh, bs := newTestDefinitionHandler(t)
+ defer dh.cleanup(t)
+
+ ctx := context.Background()
+ node1, org1, claimMsg, claimData := testNodeRegistrationAndVerification(t)
+
+ dh.mim.On("VerifyIdentityChain", ctx, node1).Return(org1, false, nil)
+ dh.mdi.On("GetIdentityByName", ctx, core.IdentityTypeNode, node1.Namespace, node1.Name).Return(nil, nil)
+ dh.mdi.On("GetIdentityByID", ctx, "ns1", node1.ID).Return(nil, nil)
+ dh.mdi.On("GetVerifierByValue", ctx, core.VerifierTypeFFDXPeerID, "ns1", "a dx").Return(nil, nil)
+ dh.mdi.On("UpsertIdentity", ctx, mock.MatchedBy(func(identity *core.Identity) bool {
+ assert.Equal(t, *claimMsg.Header.ID, *identity.Messages.Claim)
+ return true
+ }), database.UpsertOptimizationNew).Return(nil)
+ dh.mdi.On("UpsertVerifier", ctx, mock.MatchedBy(func(verifier *core.Verifier) bool {
+ assert.Equal(t, core.VerifierTypeFFDXPeerID, verifier.Type)
+ assert.Equal(t, "a dx", verifier.Value)
+ assert.Equal(t, *node1.ID, *verifier.Identity)
+ return true
+ }), database.UpsertOptimizationNew).Return(nil)
+
+ dh.mdx.On("GetPeerID", node1.Profile).Return("a dx")
+ dh.mim.On("GetLocalNodeDID", ctx).Return(node1.DID, errors.New("somehow local node isnt configured but we got this far"))
+
+ dh.multiparty = true
+ action, err := dh.HandleDefinitionBroadcast(ctx, &bs.BatchState, claimMsg, core.DataArray{claimData}, fftypes.NewUUID())
+ assert.Equal(t, HandlerResult{Action: core.ActionRetry}, action)
+ assert.Error(t, err)
+}
diff --git a/internal/definitions/handler_identity_update.go b/internal/definitions/handler_identity_update.go
index c1f793870d..db9a65b9f0 100644
--- a/internal/definitions/handler_identity_update.go
+++ b/internal/definitions/handler_identity_update.go
@@ -87,6 +87,24 @@ func (dh *definitionHandler) handleIdentityUpdate(ctx context.Context, state *co
event := core.NewEvent(core.EventTypeIdentityUpdated, identity.Namespace, identity.ID, nil, core.SystemTopicDefinitions)
return dh.database.InsertEvent(ctx, event)
})
+
+ if dh.multiparty && identity.Type == core.IdentityTypeNode {
+ nodeDID, err := dh.identity.GetLocalNodeDID(ctx)
+ if err != nil {
+ return HandlerResult{Action: core.ActionRetry}, err
+ }
+
+ if nodeDID == identity.DID {
+ state.AddFinalize(func(ctx context.Context) error {
+ err := dh.exchange.CheckNodeIdentityStatus(ctx, identity)
+ if err != nil {
+ log.L(ctx).Warnf("Failed to check node identity status relative to dataexchange: %s", err)
+ }
+ return nil
+ })
+ }
+ }
+
return HandlerResult{Action: core.ActionConfirm}, err
}
diff --git a/internal/definitions/handler_identity_update_test.go b/internal/definitions/handler_identity_update_test.go
index 7b95615518..9fa7db23ca 100644
--- a/internal/definitions/handler_identity_update_test.go
+++ b/internal/definitions/handler_identity_update_test.go
@@ -19,6 +19,7 @@ package definitions
import (
"context"
"encoding/json"
+ "errors"
"fmt"
"testing"
@@ -65,6 +66,43 @@ func testIdentityUpdate(t *testing.T) (*core.Identity, *core.Message, *core.Data
return org1, updateMsg, updateData, iu
}
+func testNodeIdentityUpdate(t *testing.T) (*core.Identity, *core.Identity, *core.Message, *core.Data, *core.IdentityUpdate) {
+ org1 := testOrgIdentity(t, "org1")
+ org1.Parent = fftypes.NewUUID() // Not involved in verification for updates, just must not change
+ node1 := testNodeIdentity(t, "node1", org1)
+
+ iu := &core.IdentityUpdate{
+ Identity: node1.IdentityBase,
+ Updates: core.IdentityProfile{
+ Profile: fftypes.JSONObject{
+ "new": "profile",
+ },
+ Description: "new description",
+ },
+ }
+ b, err := json.Marshal(&iu)
+ assert.NoError(t, err)
+ updateData := &core.Data{
+ ID: fftypes.NewUUID(),
+ Value: fftypes.JSONAnyPtrBytes(b),
+ }
+
+ updateMsg := &core.Message{
+ Header: core.MessageHeader{
+ ID: fftypes.NewUUID(),
+ Type: core.MessageTypeDefinition,
+ Tag: core.SystemTagIdentityUpdate,
+ Topics: fftypes.FFStringArray{node1.Topic()},
+ SignerRef: core.SignerRef{
+ Author: org1.DID,
+ Key: "0x12345",
+ },
+ },
+ }
+
+ return org1, node1, updateMsg, updateData, iu
+}
+
func TestHandleDefinitionIdentityUpdateOk(t *testing.T) {
dh, bs := newTestDefinitionHandler(t)
ctx := context.Background()
@@ -250,3 +288,57 @@ func TestHandleDefinitionIdentityMissingData(t *testing.T) {
bs.assertNoFinalizers()
}
+
+func TestHandleDefinitionIdentityUpdateLocalNodeOk(t *testing.T) {
+ dh, bs := newTestDefinitionHandler(t)
+ ctx := context.Background()
+
+ org1, node1, updateMsg, updateData, iu := testNodeIdentityUpdate(t)
+
+ dh.mim.On("VerifyIdentityChain", ctx, node1).Return(org1, false, nil)
+ dh.mim.On("CachedIdentityLookupByID", ctx, node1.ID).Return(node1, nil)
+ dh.mdi.On("UpsertIdentity", ctx, mock.MatchedBy(func(identity *core.Identity) bool {
+ assert.Equal(t, *updateMsg.Header.ID, *identity.Messages.Update)
+ assert.Equal(t, node1.IdentityBase, identity.IdentityBase)
+ assert.Equal(t, iu.Updates, identity.IdentityProfile)
+ return true
+ }), database.UpsertOptimizationExisting).Return(nil)
+ dh.mdi.On("InsertEvent", mock.Anything, mock.MatchedBy(func(event *core.Event) bool {
+ return event.Type == core.EventTypeIdentityUpdated
+ })).Return(nil)
+ dh.mim.On("GetLocalNodeDID", ctx).Return(node1.DID, nil)
+ dh.mdx.On("CheckNodeIdentityStatus", ctx, node1).Return(errors.New("failed to check status but no worries"))
+
+ dh.multiparty = true
+ action, err := dh.HandleDefinitionBroadcast(ctx, &bs.BatchState, updateMsg, core.DataArray{updateData}, fftypes.NewUUID())
+ assert.Equal(t, HandlerResult{Action: core.ActionConfirm}, action)
+ assert.NoError(t, err)
+
+ err = bs.RunFinalize(ctx)
+ assert.NoError(t, err)
+}
+
+func TestHandleDefinitionIdentityUpdateLocalNodeMisconfigured(t *testing.T) {
+ dh, bs := newTestDefinitionHandler(t)
+ ctx := context.Background()
+
+ org1, node1, updateMsg, updateData, iu := testNodeIdentityUpdate(t)
+
+ dh.mim.On("VerifyIdentityChain", ctx, node1).Return(org1, false, nil)
+ dh.mim.On("CachedIdentityLookupByID", ctx, node1.ID).Return(node1, nil)
+ dh.mdi.On("UpsertIdentity", ctx, mock.MatchedBy(func(identity *core.Identity) bool {
+ assert.Equal(t, *updateMsg.Header.ID, *identity.Messages.Update)
+ assert.Equal(t, node1.IdentityBase, identity.IdentityBase)
+ assert.Equal(t, iu.Updates, identity.IdentityProfile)
+ return true
+ }), database.UpsertOptimizationExisting).Return(nil)
+ dh.mdi.On("InsertEvent", mock.Anything, mock.MatchedBy(func(event *core.Event) bool {
+ return event.Type == core.EventTypeIdentityUpdated
+ })).Return(nil)
+ dh.mim.On("GetLocalNodeDID", ctx).Return(node1.DID, errors.New("no local node but somehow we got this far"))
+
+ dh.multiparty = true
+ action, err := dh.HandleDefinitionBroadcast(ctx, &bs.BatchState, updateMsg, core.DataArray{updateData}, fftypes.NewUUID())
+ assert.Equal(t, HandlerResult{Action: core.ActionRetry}, action)
+ assert.Error(t, err)
+}
diff --git a/internal/definitions/handler_network_node_test.go b/internal/definitions/handler_network_node_test.go
index 0877ee7a4d..d709efc594 100644
--- a/internal/definitions/handler_network_node_test.go
+++ b/internal/definitions/handler_network_node_test.go
@@ -122,6 +122,7 @@ func TestHandleDeprecatedNodeDefinitionOK(t *testing.T) {
})).Return(nil)
dh.mdx.On("GetPeerID", node.DX.Endpoint).Return("member_0")
dh.mdx.On("AddNode", ctx, "ns1", node.Name, node.DX.Endpoint).Return(nil)
+ dh.mim.On("GetLocalNodeDID", ctx).Return("different node", nil)
dh.multiparty = true
diff --git a/internal/events/aggregator.go b/internal/events/aggregator.go
index 70078f1788..9f630663e0 100644
--- a/internal/events/aggregator.go
+++ b/internal/events/aggregator.go
@@ -86,13 +86,17 @@ func privatePinHash(topic string, group *fftypes.Bytes32, identity string, nonce
h.Write((*group)[:])
h.Write([]byte(identity))
nonceBytes := make([]byte, 8)
- binary.BigEndian.PutUint64(nonceBytes, uint64(nonce))
+ n := uint64(0)
+ if nonce > 0 {
+ n = uint64(nonce)
+ }
+ binary.BigEndian.PutUint64(nonceBytes, n)
h.Write(nonceBytes)
return fftypes.HashResult(h)
}
func newAggregator(ctx context.Context, ns string, di database.Plugin, bi blockchain.Plugin, pm privatemessaging.Manager, sh definitions.Handler, im identity.Manager, dm data.Manager, en *eventNotifier, mm metrics.Manager, cacheManager cache.Manager) (*aggregator, error) {
- batchSize := config.GetInt(coreconfig.EventAggregatorBatchSize)
+ batchSize := config.GetUint64(coreconfig.EventAggregatorBatchSize)
ag := &aggregator{
ctx: log.WithLogField(ctx, "role", "aggregator"),
namespace: ns,
diff --git a/internal/events/batch_pin_complete_test.go b/internal/events/batch_pin_complete_test.go
index fc78d63ac8..75ee4c328c 100644
--- a/internal/events/batch_pin_complete_test.go
+++ b/internal/events/batch_pin_complete_test.go
@@ -660,8 +660,9 @@ func TestPersistBatchGoodDataMessageFail(t *testing.T) {
em.mdi.On("InsertOrGetBatch", mock.Anything, mock.Anything).Return(nil, nil)
em.mdi.On("InsertDataArray", mock.Anything, mock.Anything).Return(nil)
- em.mdi.On("InsertMessages", mock.Anything, mock.Anything, mock.AnythingOfType("database.PostCompletionHook")).Return(fmt.Errorf("optimzation miss"))
- em.mdi.On("UpsertMessage", mock.Anything, mock.Anything, database.UpsertOptimizationExisting, mock.AnythingOfType("database.PostCompletionHook")).Return(fmt.Errorf("pop"))
+ em.mdi.On("InsertMessages", mock.Anything, mock.Anything, mock.AnythingOfType("database.PostCompletionHook")).Return(fmt.Errorf("optimzation miss")).Once()
+ em.mdi.On("GetMessageIDs", mock.Anything, "ns1", mock.Anything).Return([]*core.IDAndSequence{}, nil)
+ em.mdi.On("InsertMessages", mock.Anything, mock.Anything, mock.AnythingOfType("database.PostCompletionHook")).Return(fmt.Errorf("pop")).Once()
em.mim.On("GetLocalNode", mock.Anything).Return(testNode, nil)
diff --git a/internal/events/dx_callbacks_test.go b/internal/events/dx_callbacks_test.go
index 2f356d473a..751ce3e838 100644
--- a/internal/events/dx_callbacks_test.go
+++ b/internal/events/dx_callbacks_test.go
@@ -609,7 +609,7 @@ func TestMessageReceiveMessagePersistMessageFail(t *testing.T) {
em.mdi.On("InsertOrGetBatch", em.ctx, mock.Anything).Return(nil, nil)
em.mdi.On("InsertDataArray", em.ctx, mock.Anything).Return(nil)
em.mdi.On("InsertMessages", em.ctx, mock.Anything, mock.AnythingOfType("database.PostCompletionHook")).Return(fmt.Errorf("optimization fail"))
- em.mdi.On("UpsertMessage", em.ctx, mock.Anything, database.UpsertOptimizationExisting, mock.AnythingOfType("database.PostCompletionHook")).Return(fmt.Errorf("pop"))
+ em.mdi.On("GetMessageIDs", mock.Anything, "ns1", mock.Anything).Return(nil, fmt.Errorf("pop"))
// no ack as we are simulating termination mid retry
mde := newMessageReceivedNoAck("peer1", tw)
diff --git a/internal/events/event_dispatcher.go b/internal/events/event_dispatcher.go
index f97a0174a8..7e65a0aa59 100644
--- a/internal/events/event_dispatcher.go
+++ b/internal/events/event_dispatcher.go
@@ -68,7 +68,7 @@ type eventDispatcher struct {
eventDelivery chan []*core.EventDelivery
mux sync.Mutex
namespace string
- readAhead int
+ readAhead uint64
batch bool
subscription *subscription
txHelper txcommon.Helper
@@ -76,9 +76,9 @@ type eventDispatcher struct {
func newEventDispatcher(ctx context.Context, enricher *eventEnricher, ei events.Plugin, di database.Plugin, dm data.Manager, bm broadcast.Manager, pm privatemessaging.Manager, connID string, sub *subscription, en *eventNotifier, txHelper txcommon.Helper) *eventDispatcher {
ctx, cancelCtx := context.WithCancel(ctx)
- readAhead := uint(0)
+ readAhead := uint64(0)
if sub.definition.Options.ReadAhead != nil {
- readAhead = uint(*sub.definition.Options.ReadAhead)
+ readAhead = uint64(*sub.definition.Options.ReadAhead)
}
batchTimeout := defaultBatchTimeout
@@ -105,7 +105,7 @@ func newEventDispatcher(ctx context.Context, enricher *eventEnricher, ei events.
namespace: sub.definition.Namespace,
inflight: make(map[fftypes.UUID]*core.Event),
eventDelivery: make(chan []*core.EventDelivery, readAhead+1),
- readAhead: int(readAhead),
+ readAhead: readAhead,
acksNacks: make(chan ackNack),
closed: make(chan struct{}),
txHelper: txHelper,
@@ -113,7 +113,7 @@ func newEventDispatcher(ctx context.Context, enricher *eventEnricher, ei events.
}
pollerConf := &eventPollerConf{
- eventBatchSize: config.GetInt(coreconfig.EventDispatcherBufferLength),
+ eventBatchSize: config.GetUint64(coreconfig.EventDispatcherBufferLength),
eventBatchTimeout: config.GetDuration(coreconfig.EventDispatcherBatchTimeout),
eventPollTimeout: config.GetDuration(coreconfig.EventDispatcherPollTimeout),
startupOffsetRetryAttempts: 0, // We need to keep trying to start indefinitely
@@ -143,7 +143,7 @@ func newEventDispatcher(ctx context.Context, enricher *eventEnricher, ei events.
pollerConf.eventPollTimeout = batchTimeout
}
}
- if batch || pollerConf.eventBatchSize < int(readAhead) {
+ if batch || pollerConf.eventBatchSize < readAhead {
pollerConf.eventBatchSize = ed.readAhead
}
@@ -243,9 +243,9 @@ func (ed *eventDispatcher) bufferedDelivery(events []core.LocallySequenced) (boo
for {
ed.mux.Lock()
var dispatchable []*core.EventDelivery
- inflightCount := len(ed.inflight)
+ inflightCount := uint64(len(ed.inflight))
maxDispatch := 1 + ed.readAhead - inflightCount
- if maxDispatch >= len(matching) {
+ if maxDispatch >= uint64(len(matching)) {
dispatchable = matching
matching = nil
} else if maxDispatch > 0 {
@@ -260,7 +260,7 @@ func (ed *eventDispatcher) bufferedDelivery(events []core.LocallySequenced) (boo
for _, event := range dispatchable {
ed.mux.Lock()
ed.inflight[*event.ID] = &event.Event
- inflightCount = len(ed.inflight)
+ inflightCount = uint64(len(ed.inflight))
ed.mux.Unlock()
dispatched++
diff --git a/internal/events/event_dispatcher_test.go b/internal/events/event_dispatcher_test.go
index a056c32518..a752da0a2a 100644
--- a/internal/events/event_dispatcher_test.go
+++ b/internal/events/event_dispatcher_test.go
@@ -65,7 +65,7 @@ func newTestEventDispatcher(sub *subscription) (*eventDispatcher, func()) {
}
func TestEventDispatcherStartStop(t *testing.T) {
- ten := uint16(10)
+ ten := uint(10)
oldest := core.SubOptsFirstEventOldest
ed, cancel := newTestEventDispatcher(&subscription{
dispatcherElection: make(chan bool, 1),
@@ -88,7 +88,7 @@ func TestEventDispatcherStartStop(t *testing.T) {
<-confirmedElected
}
- assert.Equal(t, int(10), ed.readAhead)
+ assert.Equal(t, uint64(10), ed.readAhead)
ed.start()
confirmedElected <- true
close(confirmedElected)
@@ -97,7 +97,7 @@ func TestEventDispatcherStartStop(t *testing.T) {
}
func TestEventDispatcherStartStopBatched(t *testing.T) {
- ten := uint16(10)
+ ten := uint(10)
oldest := core.SubOptsFirstEventOldest
truthy := true
ed, cancel := newTestEventDispatcher(&subscription{
@@ -122,7 +122,7 @@ func TestEventDispatcherStartStopBatched(t *testing.T) {
<-confirmedElected
}
- assert.Equal(t, int(10), ed.readAhead)
+ assert.Equal(t, uint64(10), ed.readAhead)
ed.start()
confirmedElected <- true
close(confirmedElected)
@@ -172,7 +172,7 @@ func TestEventDispatcherLeaderElection(t *testing.T) {
func TestEventDispatcherReadAheadOutOfOrderAcks(t *testing.T) {
log.SetLevel("debug")
- var five = uint16(5)
+ var five = uint(5)
subID := fftypes.NewUUID()
sub := &subscription{
dispatcherElection: make(chan bool, 1),
@@ -364,7 +364,7 @@ func TestEventDispatcherNoReadAheadInOrder(t *testing.T) {
func TestEventDispatcherBatchBased(t *testing.T) {
log.SetLevel("debug")
- three := uint16(3)
+ three := uint(3)
longTime := "1m"
subID := fftypes.NewUUID()
truthy := true
@@ -466,7 +466,7 @@ func TestEventDispatcherBatchBased(t *testing.T) {
func TestEventDispatcherBatchDispatchFail(t *testing.T) {
log.SetLevel("debug")
- two := uint16(2)
+ two := uint(2)
longTime := "1m"
subID := fftypes.NewUUID()
truthy := true
@@ -1202,7 +1202,7 @@ func TestDeliverEventsWithDataFail(t *testing.T) {
func TestEventDispatcherWithReply(t *testing.T) {
log.SetLevel("debug")
- var two = uint16(5)
+ var two = uint(5)
sub := &subscription{
dispatcherElection: make(chan bool, 1),
definition: &core.Subscription{
@@ -1253,7 +1253,7 @@ func TestEventDispatcherWithReply(t *testing.T) {
func TestEventDeliveryBatch(t *testing.T) {
log.SetLevel("debug")
- var five = uint16(5)
+ var five = uint(5)
truthy := true
sub := &subscription{
dispatcherElection: make(chan bool, 1),
diff --git a/internal/events/event_poller.go b/internal/events/event_poller.go
index cd509cc204..774e303788 100644
--- a/internal/events/event_poller.go
+++ b/internal/events/event_poller.go
@@ -46,7 +46,7 @@ type newEventsHandler func(events []core.LocallySequenced) (bool, error)
type eventPollerConf struct {
ephemeral bool
- eventBatchSize int
+ eventBatchSize uint64
eventBatchTimeout time.Duration
eventPollTimeout time.Duration
firstEvent *core.SubOptsFirstEvent
@@ -179,7 +179,7 @@ func (ep *eventPoller) readPage() ([]core.LocallySequenced, error) {
fb.Gt("sequence", pollingOffset),
)
filter = ep.conf.addCriteria(filter)
- items, err = ep.conf.getItems(ep.ctx, filter.Sort("sequence").Limit(uint64(ep.conf.eventBatchSize)), pollingOffset)
+ items, err = ep.conf.getItems(ep.ctx, filter.Sort("sequence").Limit(ep.conf.eventBatchSize), pollingOffset)
if err != nil {
return true, err // Retry indefinitely, until context cancelled
}
@@ -209,7 +209,7 @@ func (ep *eventPoller) eventLoop() {
return
}
- eventCount := len(events)
+ eventCount := uint64(len(events))
// We might want to wait for the batch to fill - so we delay and re-poll
if ep.conf.eventBatchTimeout > 0 && !doBatchDelay && eventCount < ep.conf.eventBatchSize {
@@ -304,7 +304,7 @@ func (ep *eventPoller) waitForBatchTimeout() {
}
}
-func (ep *eventPoller) waitForShoulderTapOrPollTimeout(lastEventCount int) bool {
+func (ep *eventPoller) waitForShoulderTapOrPollTimeout(lastEventCount uint64) bool {
l := log.L(ep.ctx)
longTimeoutDuration := ep.conf.eventPollTimeout
diff --git a/internal/events/persist_batch.go b/internal/events/persist_batch.go
index 831cfb493e..b4115d6868 100644
--- a/internal/events/persist_batch.go
+++ b/internal/events/persist_batch.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2023 Kaleido, Inc.
+// Copyright ยฉ 2024 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -18,7 +18,10 @@ package events
import (
"context"
+ "database/sql/driver"
+ "errors"
+ "github.com/hyperledger/firefly-common/pkg/ffapi"
"github.com/hyperledger/firefly-common/pkg/fftypes"
"github.com/hyperledger/firefly-common/pkg/log"
"github.com/hyperledger/firefly/pkg/core"
@@ -274,7 +277,7 @@ func (em *eventManager) persistBatchContent(ctx context.Context, batch *core.Bat
// Fall back to individual upserts
for i, data := range batch.Payload.Data {
if err := em.database.UpsertData(ctx, data, database.UpsertOptimizationExisting); err != nil {
- if err == database.HashMismatch {
+ if errors.Is(err, database.HashMismatch) {
log.L(ctx).Errorf("Invalid data entry %d in batch '%s'. Hash mismatch with existing record with same UUID '%s' Hash=%s", i, batch.ID, data.ID, data.Hash)
return false, nil
}
@@ -298,22 +301,56 @@ func (em *eventManager) persistBatchContent(ctx context.Context, batch *core.Bat
})
if err != nil {
log.L(ctx).Debugf("Batch message insert optimization failed for batch '%s': %s", batch.ID, err)
- // Fall back to individual upserts
- for i, msg := range batch.Payload.Messages {
- postHookUpdateMessageCache := func() {
- mm := matchedMsgs[i]
- em.data.UpdateMessageCache(mm.message, mm.data)
- }
- if err = em.database.UpsertMessage(ctx, msg, database.UpsertOptimizationExisting, postHookUpdateMessageCache); err != nil {
- if err == database.HashMismatch {
- log.L(ctx).Errorf("Invalid message entry %d in batch'%s'. Hash mismatch with existing record with same UUID '%s' Hash=%s", i, batch.ID, msg.Header.ID, msg.Hash)
- return false, nil // This is not retryable. skip this data entry
+
+ // Messages are immutable in their contents, and it's entirely possible we're being sent
+ // messages we've already been sent in a previous batch, and subsequently modified th
+ // state of (they've been confirmed etc.).
+ // So we find a list of those that aren't in the DB and so and insert just those.
+ var foundIDs []*core.IDAndSequence
+ foundIDs, err = em.database.GetMessageIDs(ctx, batch.Namespace, messageIDFilter(ctx, batch.Payload.Messages))
+ if err == nil {
+ remainingInserts := make([]*core.Message, 0, len(batch.Payload.Messages))
+ for _, m := range batch.Payload.Messages {
+ isFound := false
+ for _, foundID := range foundIDs {
+ if foundID.ID.Equals(m.Header.ID) {
+ isFound = true
+ log.L(ctx).Warnf("Message %s in batch '%s' is a duplicate", m.Header.ID, batch.ID)
+ break
+ }
}
- log.L(ctx).Errorf("Failed to insert message entry %d in batch '%s': %s", i, batch.ID, err)
- return false, err // a persistence failure here is considered retryable (so returned)
+ if !isFound {
+ remainingInserts = append(remainingInserts, m)
+ }
+ }
+ if len(remainingInserts) > 0 {
+ // Only the remaining ones get updates
+ err = em.database.InsertMessages(ctx, batch.Payload.Messages, func() {
+ for _, mm := range matchedMsgs {
+ for _, m := range remainingInserts {
+ if mm.message.Header.ID.Equals(m.Header.ID) {
+ em.data.UpdateMessageCache(mm.message, mm.data)
+ }
+ }
+ }
+ })
}
}
+ // If we have an error at this point, we cannot insert (must not be a duplicate)
+ if err != nil {
+ log.L(ctx).Errorf("Failed to insert messages: %s", err)
+ return false, err // a persistence failure here is considered retryable (so returned)
+ }
}
return true, nil
}
+
+func messageIDFilter(ctx context.Context, msgs []*core.Message) ffapi.Filter {
+ fb := database.MessageQueryFactory.NewFilter(ctx)
+ ids := make([]driver.Value, len(msgs))
+ for i, msg := range msgs {
+ ids[i] = msg.Header.ID
+ }
+ return fb.In("id", ids)
+}
diff --git a/internal/events/persist_batch_test.go b/internal/events/persist_batch_test.go
index 8ce8d2c49d..57d4934d39 100644
--- a/internal/events/persist_batch_test.go
+++ b/internal/events/persist_batch_test.go
@@ -225,7 +225,7 @@ func TestPersistBatchContentSentByUsNotFoundFallback(t *testing.T) {
}
-func TestPersistBatchContentSentByUsFoundMismatch(t *testing.T) {
+func TestPersistBatchContentSentByUsFoundDup(t *testing.T) {
em := newTestEventManager(t)
defer em.cleanup(t)
@@ -234,21 +234,24 @@ func TestPersistBatchContentSentByUsFoundMismatch(t *testing.T) {
batch := sampleBatch(t, core.BatchTypeBroadcast, core.TransactionTypeBatchPin, core.DataArray{data})
batch.Node = testNodeID
+ msgID := batch.Payload.Messages[0].Header.ID
em.mdm.On("GetMessageWithDataCached", em.ctx, batch.Payload.Messages[0].Header.ID).Return(&core.Message{
Header: core.MessageHeader{
- ID: fftypes.NewUUID(),
+ ID: msgID,
},
}, nil, true, nil)
em.mdi.On("InsertDataArray", mock.Anything, mock.Anything).Return(nil)
em.mdi.On("InsertMessages", mock.Anything, mock.Anything, mock.AnythingOfType("database.PostCompletionHook")).Return(fmt.Errorf("optimization miss"))
- em.mdi.On("UpsertMessage", mock.Anything, mock.Anything, database.UpsertOptimizationExisting, mock.AnythingOfType("database.PostCompletionHook")).Return(database.HashMismatch)
+ em.mdi.On("GetMessageIDs", mock.Anything, "ns1", mock.Anything).Return([]*core.IDAndSequence{
+ {ID: *msgID},
+ }, nil)
em.mim.On("GetLocalNode", mock.Anything).Return(testNode, nil)
ok, err := em.persistBatchContent(em.ctx, batch, []*messageAndData{})
assert.NoError(t, err)
- assert.False(t, ok)
+ assert.True(t, ok)
}
@@ -261,9 +264,10 @@ func TestPersistBatchContentInsertMessagesFail(t *testing.T) {
batch := sampleBatch(t, core.BatchTypeBroadcast, core.TransactionTypeBatchPin, core.DataArray{data})
em.mdi.On("InsertDataArray", mock.Anything, mock.Anything).Return(nil)
- em.mdi.On("InsertMessages", mock.Anything, mock.Anything, mock.AnythingOfType("database.PostCompletionHook")).Return(fmt.Errorf("optimization miss"))
- em.mdi.On("UpsertMessage", mock.Anything, mock.Anything, database.UpsertOptimizationExisting, mock.AnythingOfType("database.PostCompletionHook")).Return(nil).Run(func(args mock.Arguments) {
- args[3].(database.PostCompletionHook)()
+ em.mdi.On("InsertMessages", mock.Anything, mock.Anything, mock.AnythingOfType("database.PostCompletionHook")).Return(fmt.Errorf("optimization miss")).Once()
+ em.mdi.On("GetMessageIDs", mock.Anything, "ns1", mock.Anything).Return([]*core.IDAndSequence{}, nil)
+ em.mdi.On("InsertMessages", mock.Anything, mock.Anything, mock.AnythingOfType("database.PostCompletionHook")).Return(nil).Once().Run(func(args mock.Arguments) {
+ args[2].(database.PostCompletionHook)()
})
msgData := &messageAndData{
diff --git a/internal/events/subscription_manager.go b/internal/events/subscription_manager.go
index a31b937e5a..a11dcf2d6e 100644
--- a/internal/events/subscription_manager.go
+++ b/internal/events/subscription_manager.go
@@ -92,7 +92,7 @@ type subscriptionManager struct {
deletedSubscriptions chan *fftypes.UUID
retry retry.Retry
- defaultBatchSize uint16
+ defaultBatchSize uint
defaultBatchTimeout time.Duration
}
@@ -120,7 +120,7 @@ func newSubscriptionManager(ctx context.Context, ns *core.Namespace, enricher *e
MaximumDelay: config.GetDuration(coreconfig.SubscriptionsRetryMaxDelay),
Factor: config.GetFloat64(coreconfig.SubscriptionsRetryFactor),
},
- defaultBatchSize: uint16(config.GetInt(coreconfig.SubscriptionDefaultsBatchSize)),
+ defaultBatchSize: config.GetUint(coreconfig.SubscriptionDefaultsBatchSize),
defaultBatchTimeout: config.GetDuration(coreconfig.SubscriptionDefaultsBatchTimeout),
}
@@ -534,7 +534,7 @@ func (sm *subscriptionManager) connectionClosed(ei events.Plugin, connID string)
sm.mux.Lock()
conn, ok := sm.connections[connID]
if ok && conn.ei != ei {
- log.L(sm.ctx).Warnf(i18n.ExpandWithCode(sm.ctx, i18n.MessageKey(coremsgs.MsgMismatchedTransport), connID, ei.Name(), conn.ei.Name()))
+ log.L(sm.ctx).Warn(i18n.ExpandWithCode(sm.ctx, i18n.MessageKey(coremsgs.MsgMismatchedTransport), connID, ei.Name(), conn.ei.Name()))
sm.mux.Unlock()
return
}
diff --git a/internal/events/subscription_manager_test.go b/internal/events/subscription_manager_test.go
index ef509c7057..008bdff925 100644
--- a/internal/events/subscription_manager_test.go
+++ b/internal/events/subscription_manager_test.go
@@ -571,7 +571,7 @@ func TestCreateSubscriptionSuccessBatch(t *testing.T) {
})
assert.NoError(t, err)
- assert.Equal(t, uint16(50), *sub.definition.Options.ReadAhead)
+ assert.Equal(t, uint(50), *sub.definition.Options.ReadAhead)
assert.Equal(t, "50ms", *sub.definition.Options.BatchTimeout)
}
diff --git a/internal/events/system/events.go b/internal/events/system/events.go
index 354be298d7..c12c174114 100644
--- a/internal/events/system/events.go
+++ b/internal/events/system/events.go
@@ -42,7 +42,7 @@ type Events struct {
mux sync.Mutex
listeners map[string][]EventListener
connID string
- readAhead uint16
+ readAhead uint
}
type callbacks struct {
@@ -66,7 +66,7 @@ func (se *Events) Init(ctx context.Context, config config.Section) (err error) {
handlers: make(map[string]events.Callbacks),
},
listeners: make(map[string][]EventListener),
- readAhead: uint16(config.GetInt(SystemEventsConfReadAhead)),
+ readAhead: config.GetUint(SystemEventsConfReadAhead),
connID: fftypes.ShortID(),
}
return nil
diff --git a/internal/events/webhooks/webhooks_test.go b/internal/events/webhooks/webhooks_test.go
index f38ba4e0a7..958e21ba64 100644
--- a/internal/events/webhooks/webhooks_test.go
+++ b/internal/events/webhooks/webhooks_test.go
@@ -481,7 +481,23 @@ func TestRequestWithBodyReplyEndToEndWithTLS(t *testing.T) {
}()
server.Handler = r
- go server.ListenAndServeTLS(publicKeyFile.Name(), privateKeyFile.Name())
+ go func() {
+ if err := server.ListenAndServeTLS(publicKeyFile.Name(), privateKeyFile.Name()); err != nil && err != http.ErrServerClosed {
+ log.Fatalf("ListenAndServeTLS(): %v", err)
+ }
+ }()
+
+ // Wait for the server to be ready
+ for {
+ conn, err := tls.Dial("tcp", server.Addr, &tls.Config{
+ InsecureSkipVerify: true,
+ })
+ if err == nil {
+ conn.Close()
+ break
+ }
+ time.Sleep(10 * time.Millisecond)
+ }
// Build a TLS config for the client and set on the subscription object
cert, err := tls.LoadX509KeyPair(publicKeyFile.Name(), privateKeyFile.Name())
diff --git a/internal/events/websockets/websocket_connection.go b/internal/events/websockets/websocket_connection.go
index 58de422fa0..804b58d53f 100644
--- a/internal/events/websockets/websocket_connection.go
+++ b/internal/events/websockets/websocket_connection.go
@@ -102,12 +102,12 @@ func isBoolQuerySet(query url.Values, boolOption string) bool {
return hasOptionValues && (len(optionValues) == 0 || optionValues[0] != "false")
}
-func (wc *websocketConnection) getReadAhead(query url.Values, isBatch bool) *uint16 {
+func (wc *websocketConnection) getReadAhead(query url.Values, isBatch bool) *uint {
readaheadStr := query.Get("readahead")
if readaheadStr != "" {
readAheadInt, err := strconv.ParseUint(readaheadStr, 10, 16)
if err == nil {
- readahead := uint16(readAheadInt)
+ readahead := uint(readAheadInt)
return &readahead
}
}
diff --git a/internal/events/websockets/websockets_test.go b/internal/events/websockets/websockets_test.go
index 031adebdfe..cba25ebfad 100644
--- a/internal/events/websockets/websockets_test.go
+++ b/internal/events/websockets/websockets_test.go
@@ -1219,4 +1219,4 @@ func TestHandleStartWrongNamespace(t *testing.T) {
err := wc.handleStart(startMessage)
assert.Error(t, err)
assert.Regexp(t, "FF10462", err)
-}
\ No newline at end of file
+}
diff --git a/internal/identity/identitymanager.go b/internal/identity/identitymanager.go
index 18757ff8ad..78b5bbde39 100644
--- a/internal/identity/identitymanager.go
+++ b/internal/identity/identitymanager.go
@@ -51,6 +51,7 @@ type Manager interface {
CachedIdentityLookupMustExist(ctx context.Context, did string) (identity *core.Identity, retryable bool, err error)
CachedIdentityLookupNilOK(ctx context.Context, did string) (identity *core.Identity, retryable bool, err error)
GetLocalNode(ctx context.Context) (node *core.Identity, err error)
+ GetLocalNodeDID(ctx context.Context) (string, error)
GetRootOrgDID(ctx context.Context) (string, error)
GetRootOrg(ctx context.Context) (org *core.Identity, err error)
VerifyIdentityChain(ctx context.Context, identity *core.Identity) (immediateParent *core.Identity, retryable bool, err error)
@@ -103,13 +104,23 @@ func ParseKeyNormalizationConfig(strConfigVal string) int {
}
}
-func (im *identityManager) GetLocalNode(ctx context.Context) (node *core.Identity, err error) {
+// GetLocalNodeDID returns the expected local node DID based on the multiparty configuration, the node
+// identity does not need to be registered yet in order for this to succeed.
+func (im *identityManager) GetLocalNodeDID(ctx context.Context) (string, error) {
nodeName := im.multiparty.LocalNode().Name
if nodeName == "" {
- return nil, i18n.NewError(ctx, coremsgs.MsgLocalNodeNotSet)
+ return "", i18n.NewError(ctx, coremsgs.MsgLocalNodeNotSet)
}
- nodeDID := fmt.Sprintf("%s%s", core.FireFlyNodeDIDPrefix, nodeName)
+ return fmt.Sprintf("%s%s", core.FireFlyNodeDIDPrefix, nodeName), nil
+}
+
+// GetLocalNode returns the local node identity, if it has been registered and is in the DB/cache.
+func (im *identityManager) GetLocalNode(ctx context.Context) (node *core.Identity, err error) {
+ nodeDID, err := im.GetLocalNodeDID(ctx)
+ if err != nil {
+ return nil, err
+ }
node, _, err = im.CachedIdentityLookupNilOK(ctx, nodeDID)
return node, err
}
@@ -201,7 +212,7 @@ func (im *identityManager) ResolveInputVerifierRef(ctx context.Context, inputKey
}, nil
}
-// ResolveInputIdentity takes in blockchain signing input information from an API call (which may
+// ResolveInputSigningIdentity takes in blockchain signing input information from an API call (which may
// include author or key or both), and updates it with fully resolved and normalized values
func (im *identityManager) ResolveInputSigningIdentity(ctx context.Context, signerRef *core.SignerRef) (err error) {
log.L(ctx).Debugf("Resolving identity input: key='%s' author='%s'", signerRef.Key, signerRef.Author)
diff --git a/internal/metrics/batch_pin.go b/internal/metrics/batch_pin.go
index 6d0cbacb81..dc47b6620d 100644
--- a/internal/metrics/batch_pin.go
+++ b/internal/metrics/batch_pin.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2022 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -20,16 +20,16 @@ import (
"github.com/prometheus/client_golang/prometheus"
)
-var BatchPinCounter prometheus.Counter
+var BatchPinCounter *prometheus.CounterVec
// MetricsBatchPin is the prometheus metric for total number of batch pins submitted
var MetricsBatchPin = "ff_batchpin_total"
func InitBatchPinMetrics() {
- BatchPinCounter = prometheus.NewCounter(prometheus.CounterOpts{
+ BatchPinCounter = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: MetricsBatchPin,
Help: "Number of batch pins submitted",
- })
+ }, namespaceLabels)
}
func RegisterBatchPinMetrics() {
diff --git a/internal/metrics/broadcast.go b/internal/metrics/broadcast.go
index 545e398a49..412ad00a30 100644
--- a/internal/metrics/broadcast.go
+++ b/internal/metrics/broadcast.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2022 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -20,10 +20,10 @@ import (
"github.com/prometheus/client_golang/prometheus"
)
-var BroadcastSubmittedCounter prometheus.Counter
-var BroadcastConfirmedCounter prometheus.Counter
-var BroadcastRejectedCounter prometheus.Counter
-var BroadcastHistogram prometheus.Histogram
+var BroadcastSubmittedCounter *prometheus.CounterVec
+var BroadcastConfirmedCounter *prometheus.CounterVec
+var BroadcastRejectedCounter *prometheus.CounterVec
+var BroadcastHistogram *prometheus.HistogramVec
// BroadcastSubmittedCounterName is the prometheus metric for tracking the total number of broadcasts submitted
var BroadcastSubmittedCounterName = "ff_broadcast_submitted_total"
@@ -38,22 +38,22 @@ var BroadcastRejectedCounterName = "ff_broadcast_rejected_total"
var BroadcastHistogramName = "ff_broadcast_histogram"
func InitBroadcastMetrics() {
- BroadcastSubmittedCounter = prometheus.NewCounter(prometheus.CounterOpts{
+ BroadcastSubmittedCounter = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: BroadcastSubmittedCounterName,
Help: "Number of submitted broadcasts",
- })
- BroadcastConfirmedCounter = prometheus.NewCounter(prometheus.CounterOpts{
+ }, namespaceLabels)
+ BroadcastConfirmedCounter = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: BroadcastConfirmedCounterName,
Help: "Number of confirmed broadcasts",
- })
- BroadcastRejectedCounter = prometheus.NewCounter(prometheus.CounterOpts{
+ }, namespaceLabels)
+ BroadcastRejectedCounter = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: BroadcastRejectedCounterName,
Help: "Number of rejected broadcasts",
- })
- BroadcastHistogram = prometheus.NewHistogram(prometheus.HistogramOpts{
+ }, namespaceLabels)
+ BroadcastHistogram = prometheus.NewHistogramVec(prometheus.HistogramOpts{
Name: BroadcastHistogramName,
Help: "Histogram of broadcasts, bucketed by time to finished",
- })
+ }, namespaceLabels)
}
func RegisterBroadcastMetrics() {
diff --git a/internal/metrics/contracts.go b/internal/metrics/contracts.go
index baf3b9e604..f57240baa3 100644
--- a/internal/metrics/contracts.go
+++ b/internal/metrics/contracts.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2022 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
diff --git a/internal/metrics/identity.go b/internal/metrics/identity.go
new file mode 100644
index 0000000000..55ff55915a
--- /dev/null
+++ b/internal/metrics/identity.go
@@ -0,0 +1,77 @@
+// Copyright ยฉ 2025 Kaleido, Inc.
+//
+// SPDX-License-Identifier: Apache-2.0
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package metrics
+
+import (
+ "time"
+
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+var NodeIdentityDXCertMismatchGauge *prometheus.GaugeVec
+var NodeIdentityDXCertExpiryGauge *prometheus.GaugeVec
+
+const (
+ NodeIdentityDXCertMismatch = "ff_multiparty_node_identity_dx_mismatch"
+ NodeIdentityDXCertExpiry = "ff_multiparty_node_identity_dx_expiry_epoch"
+)
+
+func InitIdentityMetrics() {
+ NodeIdentityDXCertMismatchGauge = prometheus.NewGaugeVec(prometheus.GaugeOpts{
+ Name: NodeIdentityDXCertMismatch,
+ Help: "Status of node identity DX cert mismatch",
+ }, namespaceLabels)
+
+ NodeIdentityDXCertExpiryGauge = prometheus.NewGaugeVec(prometheus.GaugeOpts{
+ Name: NodeIdentityDXCertExpiry,
+ Help: "Timestamp, in Unix epoch format, of node identity DX cert's expiry",
+ }, namespaceLabels)
+}
+
+func RegisterIdentityMetrics() {
+ registry.MustRegister(NodeIdentityDXCertMismatchGauge)
+ registry.MustRegister(NodeIdentityDXCertExpiryGauge)
+}
+
+// TODO should this type live elsewhere ??
+type NodeIdentityDXCertMismatchStatus string
+
+const (
+ NodeIdentityDXCertMismatchStatusMismatched NodeIdentityDXCertMismatchStatus = "mismatched"
+ NodeIdentityDXCertMismatchStatusHealthy NodeIdentityDXCertMismatchStatus = "healthy"
+ NodeIdentityDXCertMismatchStatusUnknown NodeIdentityDXCertMismatchStatus = "unknown"
+)
+
+func (mm *metricsManager) NodeIdentityDXCertMismatch(namespace string, state NodeIdentityDXCertMismatchStatus) {
+ var gaugeState float64
+ switch state {
+ case NodeIdentityDXCertMismatchStatusMismatched:
+ gaugeState = 1.0
+ case NodeIdentityDXCertMismatchStatusHealthy:
+ gaugeState = 0.0
+ case NodeIdentityDXCertMismatchStatusUnknown:
+ fallthrough
+ default:
+ gaugeState = -1.0
+ }
+
+ NodeIdentityDXCertMismatchGauge.WithLabelValues(namespace).Set(gaugeState)
+}
+
+func (mm *metricsManager) NodeIdentityDXCertExpiry(namespace string, expiry time.Time) {
+ NodeIdentityDXCertExpiryGauge.WithLabelValues(namespace).Set(float64(expiry.UTC().Unix()))
+}
diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go
index 3169306b9b..8c1e056a2f 100644
--- a/internal/metrics/metrics.go
+++ b/internal/metrics/metrics.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2024 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -29,8 +29,10 @@ import (
var mutex = &sync.Mutex{}
+var namespaceLabels = []string{"ns"}
+
type Manager interface {
- CountBatchPin()
+ CountBatchPin(namespace string)
MessageSubmitted(msg *core.Message)
MessageConfirmed(msg *core.Message, eventType fftypes.FFEnum)
TransferSubmitted(transfer *core.TokenTransfer)
@@ -39,6 +41,8 @@ type Manager interface {
BlockchainTransaction(location, methodName string)
BlockchainQuery(location, methodName string)
BlockchainEvent(location, signature string)
+ NodeIdentityDXCertMismatch(namespace string, mismatch NodeIdentityDXCertMismatchStatus)
+ NodeIdentityDXCertExpiry(namespace string, expiry time.Time)
AddTime(id string)
GetTime(id string) time.Time
DeleteTime(id string)
@@ -54,24 +58,24 @@ type metricsManager struct {
func NewMetricsManager(ctx context.Context) Manager {
mm := &metricsManager{
ctx: ctx,
- metricsEnabled: config.GetBool(coreconfig.MetricsEnabled),
+ metricsEnabled: config.GetBool(coreconfig.DeprecatedMetricsEnabled) || config.GetBool(coreconfig.MonitoringEnabled),
timeMap: make(map[string]time.Time),
}
return mm
}
-func (mm *metricsManager) CountBatchPin() {
- BatchPinCounter.Inc()
+func (mm *metricsManager) CountBatchPin(namespace string) {
+ BatchPinCounter.WithLabelValues(namespace).Inc()
}
func (mm *metricsManager) MessageSubmitted(msg *core.Message) {
if len(msg.Header.ID.String()) > 0 {
switch msg.Header.Type {
case core.MessageTypeBroadcast:
- BroadcastSubmittedCounter.Inc()
+ BroadcastSubmittedCounter.WithLabelValues(msg.LocalNamespace).Inc()
case core.MessageTypePrivate:
- PrivateMsgSubmittedCounter.Inc()
+ PrivateMsgSubmittedCounter.WithLabelValues(msg.LocalNamespace).Inc()
}
mm.AddTime(msg.Header.ID.String())
}
@@ -87,23 +91,23 @@ func (mm *metricsManager) MessageConfirmed(msg *core.Message, eventType fftypes.
if !eventTime.IsZero() {
// Check that we recorded the submission
// as we might not be the party submitting
- BroadcastHistogram.Observe(timeElapsed)
+ BroadcastHistogram.WithLabelValues(msg.LocalNamespace).Observe(timeElapsed)
}
if eventType == core.EventTypeMessageConfirmed { // Broadcast Confirmed
- BroadcastConfirmedCounter.Inc()
+ BroadcastConfirmedCounter.WithLabelValues(msg.LocalNamespace).Inc()
} else if eventType == core.EventTypeMessageRejected { // Broadcast Rejected
- BroadcastRejectedCounter.Inc()
+ BroadcastRejectedCounter.WithLabelValues(msg.LocalNamespace).Inc()
}
case core.MessageTypePrivate:
if !eventTime.IsZero() {
// Check that we recorded the submission
// as we might not be the party submitting
- PrivateMsgHistogram.Observe(timeElapsed)
+ PrivateMsgHistogram.WithLabelValues(msg.LocalNamespace).Observe(timeElapsed)
}
if eventType == core.EventTypeMessageConfirmed { // Private Msg Confirmed
- PrivateMsgConfirmedCounter.Inc()
+ PrivateMsgConfirmedCounter.WithLabelValues(msg.LocalNamespace).Inc()
} else if eventType == core.EventTypeMessageRejected { // Private Msg Rejected
- PrivateMsgRejectedCounter.Inc()
+ PrivateMsgRejectedCounter.WithLabelValues(msg.LocalNamespace).Inc()
}
}
}
@@ -112,11 +116,11 @@ func (mm *metricsManager) TransferSubmitted(transfer *core.TokenTransfer) {
if len(transfer.LocalID.String()) > 0 {
switch transfer.Type {
case core.TokenTransferTypeMint: // Mint submitted
- MintSubmittedCounter.Inc()
+ MintSubmittedCounter.WithLabelValues(transfer.Namespace).Inc()
case core.TokenTransferTypeTransfer: // Transfer submitted
- TransferSubmittedCounter.Inc()
+ TransferSubmittedCounter.WithLabelValues(transfer.Namespace).Inc()
case core.TokenTransferTypeBurn: // Burn submitted
- BurnSubmittedCounter.Inc()
+ BurnSubmittedCounter.WithLabelValues(transfer.Namespace).Inc()
}
mm.AddTime(transfer.LocalID.String())
}
@@ -130,19 +134,19 @@ func (mm *metricsManager) TransferConfirmed(transfer *core.TokenTransfer) {
switch transfer.Type {
case core.TokenTransferTypeMint: // Mint confirmed
if !transferEvent.IsZero() {
- MintHistogram.Observe(timeElapsed)
+ MintHistogram.WithLabelValues(transfer.Namespace).Observe(timeElapsed)
}
- MintConfirmedCounter.Inc()
+ MintConfirmedCounter.WithLabelValues(transfer.Namespace).Inc()
case core.TokenTransferTypeTransfer: // Transfer confirmed
if !transferEvent.IsZero() {
- TransferHistogram.Observe(timeElapsed)
+ TransferHistogram.WithLabelValues(transfer.Namespace).Observe(timeElapsed)
}
- TransferConfirmedCounter.Inc()
+ TransferConfirmedCounter.WithLabelValues(transfer.Namespace).Inc()
case core.TokenTransferTypeBurn: // Burn confirmed
if !transferEvent.IsZero() {
- BurnHistogram.Observe(timeElapsed)
+ BurnHistogram.WithLabelValues(transfer.Namespace).Observe(timeElapsed)
}
- BurnConfirmedCounter.Inc()
+ BurnConfirmedCounter.WithLabelValues(transfer.Namespace).Inc()
}
}
diff --git a/internal/metrics/metrics_test.go b/internal/metrics/metrics_test.go
index 7e8c685f46..caa0e4c110 100644
--- a/internal/metrics/metrics_test.go
+++ b/internal/metrics/metrics_test.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2022 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -62,7 +62,7 @@ func newTestMetricsManager(t *testing.T) (*metricsManager, func()) {
func TestCountBatchPin(t *testing.T) {
mm, cancel := newTestMetricsManager(t)
defer cancel()
- mm.CountBatchPin()
+ mm.CountBatchPin("a-ns")
}
func TestMessageSubmittedBroadcast(t *testing.T) {
@@ -228,3 +228,44 @@ func TestIsMetricsEnabledFalse(t *testing.T) {
mm.metricsEnabled = false
assert.Equal(t, mm.IsMetricsEnabled(), false)
}
+
+func TestNodeIdentityDXCertMismatchSetsMismatchedState(t *testing.T) {
+ mm, cancel := newTestMetricsManager(t)
+ defer cancel()
+ mm.NodeIdentityDXCertMismatch("test-namespace", NodeIdentityDXCertMismatchStatusMismatched)
+ gaugeValue := testutil.ToFloat64(NodeIdentityDXCertMismatchGauge.WithLabelValues("test-namespace"))
+ assert.Equal(t, 1.0, gaugeValue)
+}
+
+func TestNodeIdentityDXCertMismatchSetsHealthyState(t *testing.T) {
+ mm, cancel := newTestMetricsManager(t)
+ defer cancel()
+ mm.NodeIdentityDXCertMismatch("test-namespace", NodeIdentityDXCertMismatchStatusHealthy)
+ gaugeValue := testutil.ToFloat64(NodeIdentityDXCertMismatchGauge.WithLabelValues("test-namespace"))
+ assert.Equal(t, 0.0, gaugeValue)
+}
+
+func TestNodeIdentityDXCertMismatchSetsUnknownState(t *testing.T) {
+ mm, cancel := newTestMetricsManager(t)
+ defer cancel()
+ mm.NodeIdentityDXCertMismatch("test-namespace", NodeIdentityDXCertMismatchStatusUnknown)
+ gaugeValue := testutil.ToFloat64(NodeIdentityDXCertMismatchGauge.WithLabelValues("test-namespace"))
+ assert.Equal(t, -1.0, gaugeValue)
+}
+
+func TestNodeIdentityDXCertMismatchSetsDefaultState(t *testing.T) {
+ mm, cancel := newTestMetricsManager(t)
+ defer cancel()
+ mm.NodeIdentityDXCertMismatch("test-namespace", "invalid-state")
+ gaugeValue := testutil.ToFloat64(NodeIdentityDXCertMismatchGauge.WithLabelValues("test-namespace"))
+ assert.Equal(t, -1.0, gaugeValue)
+}
+
+func TestNodeIdentityDXCertExpiry(t *testing.T) {
+ mm, cancel := newTestMetricsManager(t)
+ defer cancel()
+ now := time.Now().UTC()
+ mm.NodeIdentityDXCertExpiry("test-namespace", now)
+ gaugeValue := testutil.ToFloat64(NodeIdentityDXCertExpiryGauge.WithLabelValues("test-namespace"))
+ assert.Equal(t, float64(now.Unix()), gaugeValue)
+}
diff --git a/internal/metrics/private_msg.go b/internal/metrics/private_msg.go
index de654e3a88..a6d7355f8e 100644
--- a/internal/metrics/private_msg.go
+++ b/internal/metrics/private_msg.go
@@ -20,10 +20,10 @@ import (
"github.com/prometheus/client_golang/prometheus"
)
-var PrivateMsgSubmittedCounter prometheus.Counter
-var PrivateMsgConfirmedCounter prometheus.Counter
-var PrivateMsgRejectedCounter prometheus.Counter
-var PrivateMsgHistogram prometheus.Histogram
+var PrivateMsgSubmittedCounter *prometheus.CounterVec
+var PrivateMsgConfirmedCounter *prometheus.CounterVec
+var PrivateMsgRejectedCounter *prometheus.CounterVec
+var PrivateMsgHistogram *prometheus.HistogramVec
// PrivateMsgSubmittedCounterName is the prometheus metric for tracking the total number of private messages submitted
var PrivateMsgSubmittedCounterName = "ff_private_msg_submitted_total"
@@ -40,22 +40,22 @@ var PrivateMsgRejectedCounterName = "ff_private_msg_rejected_total"
var PrivateMsgHistogramName = "ff_private_msg_histogram"
func InitPrivateMsgMetrics() {
- PrivateMsgSubmittedCounter = prometheus.NewCounter(prometheus.CounterOpts{
+ PrivateMsgSubmittedCounter = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: PrivateMsgSubmittedCounterName,
Help: "Number of submitted private messages",
- })
- PrivateMsgConfirmedCounter = prometheus.NewCounter(prometheus.CounterOpts{
+ }, namespaceLabels)
+ PrivateMsgConfirmedCounter = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: PrivateMsgConfirmedCounterName,
Help: "Number of confirmed private messages",
- })
- PrivateMsgRejectedCounter = prometheus.NewCounter(prometheus.CounterOpts{
+ }, namespaceLabels)
+ PrivateMsgRejectedCounter = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: PrivateMsgRejectedCounterName,
Help: "Number of rejected private messages",
- })
- PrivateMsgHistogram = prometheus.NewHistogram(prometheus.HistogramOpts{
+ }, namespaceLabels)
+ PrivateMsgHistogram = prometheus.NewHistogramVec(prometheus.HistogramOpts{
Name: PrivateMsgHistogramName,
Help: "Histogram of private messages, bucketed by time to finished",
- })
+ }, namespaceLabels)
}
func RegisterPrivateMsgMetrics() {
diff --git a/internal/metrics/prometheus.go b/internal/metrics/prometheus.go
index f9576e8498..6bf09f93ea 100644
--- a/internal/metrics/prometheus.go
+++ b/internal/metrics/prometheus.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2022 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -88,6 +88,7 @@ func initMetricsCollectors() {
InitTokenBurnMetrics()
InitBatchPinMetrics()
InitBlockchainMetrics()
+ InitIdentityMetrics()
}
func registerMetricsCollectors() {
@@ -101,4 +102,5 @@ func registerMetricsCollectors() {
RegisterTokenTransferMetrics()
RegisterTokenBurnMetrics()
RegisterBlockchainMetrics()
+ RegisterIdentityMetrics()
}
diff --git a/internal/metrics/prometheus_test.go b/internal/metrics/prometheus_test.go
index 6a7770d00b..b0846a95d0 100644
--- a/internal/metrics/prometheus_test.go
+++ b/internal/metrics/prometheus_test.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2022 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
diff --git a/internal/metrics/token_burn.go b/internal/metrics/token_burn.go
index 9b0eefea7f..7cc6b33d6b 100644
--- a/internal/metrics/token_burn.go
+++ b/internal/metrics/token_burn.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2022 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -20,10 +20,10 @@ import (
"github.com/prometheus/client_golang/prometheus"
)
-var BurnSubmittedCounter prometheus.Counter
-var BurnConfirmedCounter prometheus.Counter
-var BurnRejectedCounter prometheus.Counter
-var BurnHistogram prometheus.Histogram
+var BurnSubmittedCounter *prometheus.CounterVec
+var BurnConfirmedCounter *prometheus.CounterVec
+var BurnRejectedCounter *prometheus.CounterVec
+var BurnHistogram *prometheus.HistogramVec
// BurnSubmittedCounterName is the prometheus metric for tracking the total number of burns submitted
var BurnSubmittedCounterName = "ff_burn_submitted_total"
@@ -38,22 +38,22 @@ var BurnRejectedCounterName = "ff_burn_rejected_total"
var BurnHistogramName = "ff_burn_histogram"
func InitTokenBurnMetrics() {
- BurnSubmittedCounter = prometheus.NewCounter(prometheus.CounterOpts{
+ BurnSubmittedCounter = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: BurnSubmittedCounterName,
Help: "Number of submitted burns",
- })
- BurnConfirmedCounter = prometheus.NewCounter(prometheus.CounterOpts{
+ }, namespaceLabels)
+ BurnConfirmedCounter = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: BurnConfirmedCounterName,
Help: "Number of confirmed burns",
- })
- BurnRejectedCounter = prometheus.NewCounter(prometheus.CounterOpts{
+ }, namespaceLabels)
+ BurnRejectedCounter = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: BurnRejectedCounterName,
Help: "Number of rejected burns",
- })
- BurnHistogram = prometheus.NewHistogram(prometheus.HistogramOpts{
+ }, namespaceLabels)
+ BurnHistogram = prometheus.NewHistogramVec(prometheus.HistogramOpts{
Name: BurnHistogramName,
Help: "Histogram of burns, bucketed by time to finished",
- })
+ }, namespaceLabels)
}
func RegisterTokenBurnMetrics() {
diff --git a/internal/metrics/token_mint.go b/internal/metrics/token_mint.go
index 36aa9eb4dd..1d6eea674d 100644
--- a/internal/metrics/token_mint.go
+++ b/internal/metrics/token_mint.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2022 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -20,10 +20,10 @@ import (
"github.com/prometheus/client_golang/prometheus"
)
-var MintSubmittedCounter prometheus.Counter
-var MintConfirmedCounter prometheus.Counter
-var MintRejectedCounter prometheus.Counter
-var MintHistogram prometheus.Histogram
+var MintSubmittedCounter *prometheus.CounterVec
+var MintConfirmedCounter *prometheus.CounterVec
+var MintRejectedCounter *prometheus.CounterVec
+var MintHistogram *prometheus.HistogramVec
// MintSubmittedCounterName is the prometheus metric for tracking the total number of mints submitted
var MintSubmittedCounterName = "ff_mint_submitted_total"
@@ -38,22 +38,22 @@ var MintRejectedCounterName = "ff_mint_rejected_total"
var MintHistogramName = "ff_mint_histogram"
func InitTokenMintMetrics() {
- MintSubmittedCounter = prometheus.NewCounter(prometheus.CounterOpts{
+ MintSubmittedCounter = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: MintSubmittedCounterName,
Help: "Number of submitted mints",
- })
- MintConfirmedCounter = prometheus.NewCounter(prometheus.CounterOpts{
+ }, namespaceLabels)
+ MintConfirmedCounter = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: MintConfirmedCounterName,
Help: "Number of confirmed mints",
- })
- MintRejectedCounter = prometheus.NewCounter(prometheus.CounterOpts{
+ }, namespaceLabels)
+ MintRejectedCounter = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: MintRejectedCounterName,
Help: "Number of rejected mints",
- })
- MintHistogram = prometheus.NewHistogram(prometheus.HistogramOpts{
+ }, namespaceLabels)
+ MintHistogram = prometheus.NewHistogramVec(prometheus.HistogramOpts{
Name: MintHistogramName,
Help: "Histogram of mints, bucketed by time to finished",
- })
+ }, namespaceLabels)
}
func RegisterTokenMintMetrics() {
diff --git a/internal/metrics/token_transfer.go b/internal/metrics/token_transfer.go
index 0aaf2571ac..e3a16008b6 100644
--- a/internal/metrics/token_transfer.go
+++ b/internal/metrics/token_transfer.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2022 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -20,10 +20,10 @@ import (
"github.com/prometheus/client_golang/prometheus"
)
-var TransferSubmittedCounter prometheus.Counter
-var TransferConfirmedCounter prometheus.Counter
-var TransferRejectedCounter prometheus.Counter
-var TransferHistogram prometheus.Histogram
+var TransferSubmittedCounter *prometheus.CounterVec
+var TransferConfirmedCounter *prometheus.CounterVec
+var TransferRejectedCounter *prometheus.CounterVec
+var TransferHistogram *prometheus.HistogramVec
// TransferSubmittedCounterName is the prometheus metric for tracking the total number of transfers submitted
var TransferSubmittedCounterName = "ff_transfer_submitted_total"
@@ -38,22 +38,22 @@ var TransferRejectedCounterName = "ff_transfer_rejected_total"
var TransferHistogramName = "ff_transfer_histogram"
func InitTokenTransferMetrics() {
- TransferSubmittedCounter = prometheus.NewCounter(prometheus.CounterOpts{
+ TransferSubmittedCounter = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: TransferSubmittedCounterName,
Help: "Number of submitted transfers",
- })
- TransferConfirmedCounter = prometheus.NewCounter(prometheus.CounterOpts{
+ }, namespaceLabels)
+ TransferConfirmedCounter = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: TransferConfirmedCounterName,
Help: "Number of confirmed transfers",
- })
- TransferRejectedCounter = prometheus.NewCounter(prometheus.CounterOpts{
+ }, namespaceLabels)
+ TransferRejectedCounter = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: TransferRejectedCounterName,
Help: "Number of rejected transfers",
- })
- TransferHistogram = prometheus.NewHistogram(prometheus.HistogramOpts{
+ }, namespaceLabels)
+ TransferHistogram = prometheus.NewHistogramVec(prometheus.HistogramOpts{
Name: TransferHistogramName,
Help: "Histogram of transfers, bucketed by time to finished",
- })
+ }, namespaceLabels)
}
func RegisterTokenTransferMetrics() {
diff --git a/internal/multiparty/manager.go b/internal/multiparty/manager.go
index 5ac4ac35b0..d1ffd058b5 100644
--- a/internal/multiparty/manager.go
+++ b/internal/multiparty/manager.go
@@ -283,7 +283,7 @@ func (mm *multipartyManager) SubmitBatchPin(ctx context.Context, batch *core.Bat
}
if mm.metrics.IsMetricsEnabled() {
- mm.metrics.CountBatchPin()
+ mm.metrics.CountBatchPin(mm.namespace.Name)
}
_, err := mm.operations.RunOperation(ctx, opBatchPin(op, batch, contexts, payloadRef), idempotentSubmit)
return err
diff --git a/internal/multiparty/manager_test.go b/internal/multiparty/manager_test.go
index dc9392c8c5..1a4ebefe9c 100644
--- a/internal/multiparty/manager_test.go
+++ b/internal/multiparty/manager_test.go
@@ -485,7 +485,7 @@ func TestSubmitPinnedBatchWithMetricsOk(t *testing.T) {
return true
})).Return(nil)
mp.mmi.On("IsMetricsEnabled").Return(true)
- mp.mmi.On("CountBatchPin").Return()
+ mp.mmi.On("CountBatchPin", "ns1").Return()
mp.mom.On("RunOperation", mock.Anything, mock.MatchedBy(func(op *core.PreparedOperation) bool {
data := op.Data.(txcommon.BatchPinData)
return op.Type == core.OpTypeBlockchainPinBatch && data.Batch == batch
@@ -618,7 +618,7 @@ func TestSubmitBatchPinWithBatchOpNotFound(t *testing.T) {
return true
})).Return(nil)
mp.mmi.On("IsMetricsEnabled").Return(true)
- mp.mmi.On("CountBatchPin").Return()
+ mp.mmi.On("CountBatchPin", "ns1").Return()
mp.mom.On("RunOperation", mock.Anything, mock.MatchedBy(func(op *core.PreparedOperation) bool {
data := op.Data.(txcommon.BatchPinData)
return op.Type == core.OpTypeBlockchainPinBatch && data.Batch == batch
diff --git a/internal/namespace/configreload_test.go b/internal/namespace/configreload_test.go
index 9afd00b91d..214fc7d0f1 100644
--- a/internal/namespace/configreload_test.go
+++ b/internal/namespace/configreload_test.go
@@ -413,7 +413,7 @@ func mockInitConfig(nmm *nmMocks) {
nmm.mdi.On("Init", mock.Anything, mock.Anything).Return(nil)
nmm.mdi.On("SetHandler", database.GlobalHandler, mock.Anything).Return()
nmm.mbi.On("Init", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
- nmm.mdx.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil)
+ nmm.mdx.On("Init", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
nmm.mps.On("Init", mock.Anything, mock.Anything).Return(nil)
nmm.mti[1].On("Init", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
nmm.mei[0].On("Init", mock.Anything, mock.Anything).Return(nil)
diff --git a/internal/namespace/manager.go b/internal/namespace/manager.go
index 65a82714a2..962043c844 100644
--- a/internal/namespace/manager.go
+++ b/internal/namespace/manager.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2024 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -161,7 +161,7 @@ func stringSlicesEqual(a, b []string) bool {
func NewNamespaceManager() Manager {
nm := &namespaceManager{
namespaces: make(map[string]*namespace),
- metricsEnabled: config.GetBool(coreconfig.MetricsEnabled),
+ metricsEnabled: config.GetBool(coreconfig.DeprecatedMetricsEnabled) || config.GetBool(coreconfig.MonitoringEnabled),
tokenBroadcastNames: make(map[string]string),
watchConfig: viper.WatchConfig,
@@ -702,7 +702,7 @@ func (nm *namespaceManager) initPlugins(pluginsToStart map[string]*plugin) (err
return err
}
case pluginCategoryDataexchange:
- if err = p.dataexchange.Init(p.ctx, nm.cancelCtx /* allow plugin to stop whole process */, p.config); err != nil {
+ if err = p.dataexchange.Init(p.ctx, nm.cancelCtx /* allow plugin to stop whole process */, p.config, nm.metrics); err != nil {
return err
}
case pluginCategorySharedstorage:
diff --git a/internal/namespace/manager_test.go b/internal/namespace/manager_test.go
index 9dce67d2b6..86c63ff835 100644
--- a/internal/namespace/manager_test.go
+++ b/internal/namespace/manager_test.go
@@ -273,7 +273,7 @@ func newTestNamespaceManager(t *testing.T, initConfig bool) (*namespaceManager,
nmm.mdi.On("Init", mock.Anything, mock.Anything).Return(nil).Once()
nmm.mdi.On("SetHandler", database.GlobalHandler, mock.Anything).Return().Once()
nmm.mbi.On("Init", mock.Anything, mock.Anything, mock.Anything, nmm.mmi, mock.Anything).Return(nil).Once()
- nmm.mdx.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
+ nmm.mdx.On("Init", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
nmm.mps.On("Init", mock.Anything, mock.Anything).Return(nil).Once()
nmm.mti[0].On("Init", mock.Anything, mock.Anything, "erc721", mock.Anything).Return(nil).Once()
nmm.mti[1].On("Init", mock.Anything, mock.Anything, "erc1155", mock.Anything).Return(nil).Once()
@@ -363,7 +363,7 @@ func TestInitDataExchangeFail(t *testing.T) {
nm, nmm, cleanup := newTestNamespaceManager(t, true)
defer cleanup()
- nmm.mdx.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("pop"))
+ nmm.mdx.On("Init", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("pop"))
err := nm.initPlugins(map[string]*plugin{
"ffdx": nm.plugins["ffdx"],
@@ -1448,7 +1448,9 @@ namespaces:
assert.NoError(t, err)
assert.NotNil(t, tlsConfigs["myconfig"])
assert.True(t, tlsConfigs["myconfig"].RootCAs.Equal(expectedTLSConfig.RootCAs))
- assert.Equal(t, tlsConfigs["myconfig"].Certificates, expectedTLSConfig.Certificates)
+ certificate, err := tlsConfigs["myconfig"].GetCertificate(nil)
+ assert.NoError(t, err)
+ assert.Equal(t, *certificate, cert)
}
func TestLoadTLSConfigsDuplicateConfigs(t *testing.T) {
diff --git a/internal/networkmap/check_node.go b/internal/networkmap/check_node.go
new file mode 100644
index 0000000000..fc1bdbe54e
--- /dev/null
+++ b/internal/networkmap/check_node.go
@@ -0,0 +1,30 @@
+// Copyright ยฉ 2025 Kaleido, Inc.
+//
+// SPDX-License-Identifier: Apache-2.0
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package networkmap
+
+import (
+ "context"
+)
+
+func (nm *networkMap) CheckNodeIdentityStatus(ctx context.Context) error {
+ node, err := nm.identity.GetLocalNode(ctx)
+ if err != nil {
+ return err
+ }
+
+ return nm.exchange.CheckNodeIdentityStatus(ctx, node)
+}
diff --git a/internal/networkmap/check_node_test.go b/internal/networkmap/check_node_test.go
new file mode 100644
index 0000000000..3955b45f21
--- /dev/null
+++ b/internal/networkmap/check_node_test.go
@@ -0,0 +1,84 @@
+// Copyright ยฉ 2025 Kaleido, Inc.
+//
+// SPDX-License-Identifier: Apache-2.0
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package networkmap
+
+import (
+ "context"
+ "errors"
+ "testing"
+
+ "github.com/hyperledger/firefly-common/pkg/fftypes"
+ "github.com/hyperledger/firefly/mocks/dataexchangemocks"
+ "github.com/hyperledger/firefly/mocks/identitymanagermocks"
+ "github.com/hyperledger/firefly/pkg/core"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestCheckNodeIdentityStatusSuccess(t *testing.T) {
+ nm, cancel := newTestNetworkmap(t)
+ defer cancel()
+ ctx := context.TODO()
+
+ aProfile := fftypes.JSONAnyPtr(`{"cert": "a-cert" }`).JSONObject()
+ node := &core.Identity{
+ IdentityProfile: core.IdentityProfile{
+ Profile: aProfile,
+ },
+ }
+ nm.identity.(*identitymanagermocks.Manager).On("GetLocalNode", ctx).Return(node, nil)
+ nm.exchange.(*dataexchangemocks.Plugin).On("CheckNodeIdentityStatus", ctx, node).Return(nil)
+
+ err := nm.CheckNodeIdentityStatus(context.TODO())
+ assert.NoError(t, err)
+
+ nm.identity.(*identitymanagermocks.Manager).AssertExpectations(t)
+ nm.exchange.(*dataexchangemocks.Plugin).AssertExpectations(t)
+}
+
+func TestCheckNodeIdentityStatusLocalNodeFails(t *testing.T) {
+ nm, cancel := newTestNetworkmap(t)
+ defer cancel()
+ ctx := context.TODO()
+
+ nm.identity.(*identitymanagermocks.Manager).On("GetLocalNode", ctx).Return(&core.Identity{}, errors.New("local node not set"))
+
+ err := nm.CheckNodeIdentityStatus(ctx)
+ assert.Error(t, err)
+
+ nm.identity.(*identitymanagermocks.Manager).AssertExpectations(t)
+}
+
+func TestCheckNodeIdentityStatusFails(t *testing.T) {
+ nm, cancel := newTestNetworkmap(t)
+ defer cancel()
+ ctx := context.TODO()
+
+ aProfile := fftypes.JSONAnyPtr(`{"cert": "a-cert" }`).JSONObject()
+ node := &core.Identity{
+ IdentityProfile: core.IdentityProfile{
+ Profile: aProfile,
+ },
+ }
+ nm.identity.(*identitymanagermocks.Manager).On("GetLocalNode", ctx).Return(node, nil)
+ nm.exchange.(*dataexchangemocks.Plugin).On("CheckNodeIdentityStatus", ctx, node).Return(errors.New("identity status check failed"))
+
+ err := nm.CheckNodeIdentityStatus(context.TODO())
+ assert.Error(t, err)
+
+ nm.identity.(*identitymanagermocks.Manager).AssertExpectations(t)
+ nm.exchange.(*dataexchangemocks.Plugin).AssertExpectations(t)
+}
diff --git a/internal/networkmap/manager.go b/internal/networkmap/manager.go
index bb45434704..364c0a6a07 100644
--- a/internal/networkmap/manager.go
+++ b/internal/networkmap/manager.go
@@ -37,6 +37,7 @@ type Manager interface {
RegisterNodeOrganization(ctx context.Context, waitConfirm bool) (org *core.Identity, err error)
RegisterIdentity(ctx context.Context, dto *core.IdentityCreateDTO, waitConfirm bool) (identity *core.Identity, err error)
UpdateIdentity(ctx context.Context, id string, dto *core.IdentityUpdateDTO, waitConfirm bool) (identity *core.Identity, err error)
+ CheckNodeIdentityStatus(ctx context.Context) error
GetOrganizationByNameOrID(ctx context.Context, nameOrID string) (*core.Identity, error)
GetOrganizations(ctx context.Context, filter ffapi.AndFilter) ([]*core.Identity, *ffapi.FilterResult, error)
diff --git a/internal/networkmap/register_node.go b/internal/networkmap/register_node.go
index 3b5a0b6978..e7850ff403 100644
--- a/internal/networkmap/register_node.go
+++ b/internal/networkmap/register_node.go
@@ -25,7 +25,6 @@ import (
)
func (nm *networkMap) RegisterNode(ctx context.Context, waitConfirm bool) (identity *core.Identity, err error) {
-
nodeOwningOrg, err := nm.identity.GetRootOrg(ctx)
if err != nil {
return nil, err
diff --git a/internal/networkmap/register_node_test.go b/internal/networkmap/register_node_test.go
index 5f1e2fd1a9..4789833e2f 100644
--- a/internal/networkmap/register_node_test.go
+++ b/internal/networkmap/register_node_test.go
@@ -45,10 +45,11 @@ func TestRegisterNodeOk(t *testing.T) {
mim.On("ResolveIdentitySigner", nm.ctx, parentOrg).Return(signerRef, nil)
mdx := nm.exchange.(*dataexchangemocks.Plugin)
- mdx.On("GetEndpointInfo", nm.ctx, "node1").Return(fftypes.JSONObject{
+ dxPeer := fftypes.JSONObject{
"id": "peer1",
"endpoint": "details",
- }, nil)
+ }
+ mdx.On("GetEndpointInfo", nm.ctx, "node1").Return(dxPeer, nil)
mds := nm.defsender.(*definitionsmocks.Sender)
mds.On("ClaimIdentity", nm.ctx,
@@ -124,5 +125,4 @@ func TestRegisterNodeGetOwnerFail(t *testing.T) {
_, err := nm.RegisterNode(nm.ctx, false)
assert.Regexp(t, "pop", err)
-
}
diff --git a/internal/networkmap/update_identity.go b/internal/networkmap/update_identity.go
index d675c8e75b..af1f7c9df0 100644
--- a/internal/networkmap/update_identity.go
+++ b/internal/networkmap/update_identity.go
@@ -44,6 +44,11 @@ func (nm *networkMap) updateIdentityID(ctx context.Context, id *fftypes.UUID, dt
return nil, i18n.NewError(ctx, coremsgs.Msg404NoResult)
}
+ // TODO is this right ? code below assumes this is true and errors otherwise
+ if dto.IdentityProfile.Profile == nil {
+ return nil, i18n.NewError(ctx, coremsgs.MsgInvalidIdentityPatch)
+ }
+
// We can't sparse merge the generic JSON fields, but we need to propagate the ID
if dto.IdentityProfile.Profile.GetString("id") == "" {
existingID := identity.IdentityProfile.Profile.GetString("id")
diff --git a/internal/networkmap/update_identity_test.go b/internal/networkmap/update_identity_test.go
index 08507082b7..c19977a6e2 100644
--- a/internal/networkmap/update_identity_test.go
+++ b/internal/networkmap/update_identity_test.go
@@ -268,3 +268,16 @@ func TestUpdateIdentityProfileOverwrite(t *testing.T) {
mim.AssertExpectations(t)
mds.AssertExpectations(t)
}
+
+func TestUpdateIdentityProfileNotProvided(t *testing.T) {
+ nm, cancel := newTestNetworkmap(t)
+ defer cancel()
+
+ identity := testOrg("org1")
+
+ mim := nm.identity.(*identitymanagermocks.Manager)
+ mim.On("CachedIdentityLookupByID", nm.ctx, identity.ID).Return(identity, nil)
+
+ _, err := nm.UpdateIdentity(nm.ctx, identity.ID.String(), &core.IdentityUpdateDTO{}, true)
+ assert.Regexp(t, "FF10480", err)
+}
diff --git a/internal/operations/manager.go b/internal/operations/manager.go
index 27e67c5dc1..1c9c1ae27d 100644
--- a/internal/operations/manager.go
+++ b/internal/operations/manager.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2024 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -47,7 +47,8 @@ type Manager interface {
ResubmitOperations(ctx context.Context, txID *fftypes.UUID) (total int, resubmit []*core.Operation, err error)
AddOrReuseOperation(ctx context.Context, op *core.Operation, hooks ...database.PostCompletionHook) error
BulkInsertOperations(ctx context.Context, ops ...*core.Operation) error
- SubmitOperationUpdate(update *core.OperationUpdate)
+ SubmitBulkOperationUpdates(ctx context.Context, updates []*core.OperationUpdate) error
+ SubmitOperationUpdate(update *core.OperationUpdateAsync)
GetOperationByIDCached(ctx context.Context, opID *fftypes.UUID) (*core.Operation, error)
ResolveOperationByID(ctx context.Context, opID *fftypes.UUID, op *core.OperationUpdateDTO) error
Start() error
@@ -77,6 +78,18 @@ type operationsManager struct {
cache cache.CInterface
}
+// SubmitBulkOperationUpdate implements Manager.
+func (om *operationsManager) SubmitBulkOperationUpdates(ctx context.Context, updates []*core.OperationUpdate) error {
+ for _, update := range updates {
+ errString := ""
+ if update.ErrorMessage != "" {
+ errString = fmt.Sprintf(" error=%s", update.ErrorMessage)
+ }
+ log.L(om.ctx).Debugf("%s updating operation %s status=%s%s", update.Plugin, update.NamespacedOpID, update.Status, errString)
+ }
+ return om.updater.SubmitBulkOperationUpdates(ctx, updates)
+}
+
func NewOperationsManager(ctx context.Context, ns string, di database.Plugin, txHelper txcommon.Helper, cacheManager cache.Manager) (Manager, error) {
if di == nil || txHelper == nil {
return nil, i18n.NewError(ctx, coremsgs.MsgInitializationNilDepError, "OperationsManager")
@@ -193,12 +206,14 @@ func (om *operationsManager) RunOperation(ctx context.Context, op *core.Prepared
// Ok, we're failed
failState = core.OpStatusFailed
}
- om.SubmitOperationUpdate(&core.OperationUpdate{
- NamespacedOpID: op.NamespacedIDString(),
- Plugin: op.Plugin,
- Status: failState,
- ErrorMessage: err.Error(),
- Output: outputs,
+ om.SubmitOperationUpdate(&core.OperationUpdateAsync{
+ OperationUpdate: core.OperationUpdate{
+ NamespacedOpID: op.NamespacedIDString(),
+ Plugin: op.Plugin,
+ Status: failState,
+ ErrorMessage: err.Error(),
+ Output: outputs,
+ },
})
} else {
// No error so move us from "Initialized" to "Pending"
@@ -209,11 +224,13 @@ func (om *operationsManager) RunOperation(ctx context.Context, op *core.Prepared
newState = core.OpStatusSucceeded
}
- om.SubmitOperationUpdate(&core.OperationUpdate{
- NamespacedOpID: op.NamespacedIDString(),
- Plugin: op.Plugin,
- Status: newState,
- Output: outputs,
+ om.SubmitOperationUpdate(&core.OperationUpdateAsync{
+ OperationUpdate: core.OperationUpdate{
+ NamespacedOpID: op.NamespacedIDString(),
+ Plugin: op.Plugin,
+ Status: newState,
+ Output: outputs,
+ },
})
}
return outputs, err
@@ -284,7 +301,7 @@ func (om *operationsManager) ResolveOperationByID(ctx context.Context, opID *fft
return om.updater.resolveOperation(ctx, om.namespace, opID, op.Status, op.Error, op.Output)
}
-func (om *operationsManager) SubmitOperationUpdate(update *core.OperationUpdate) {
+func (om *operationsManager) SubmitOperationUpdate(update *core.OperationUpdateAsync) {
errString := ""
if update.ErrorMessage != "" {
errString = fmt.Sprintf(" error=%s", update.ErrorMessage)
diff --git a/internal/operations/manager_test.go b/internal/operations/manager_test.go
index 626dc7292f..2be14fdc1b 100644
--- a/internal/operations/manager_test.go
+++ b/internal/operations/manager_test.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2024 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -186,8 +186,8 @@ func TestRunOperationSyncSuccess(t *testing.T) {
om, cancel := newTestOperations(t)
defer cancel()
- om.updater.workQueues = []chan *core.OperationUpdate{
- make(chan *core.OperationUpdate),
+ om.updater.workQueues = []chan *core.OperationUpdateAsync{
+ make(chan *core.OperationUpdateAsync),
}
om.updater.cancelFunc()
@@ -208,8 +208,8 @@ func TestRunOperationFailIdempotentInit(t *testing.T) {
om, cancel := newTestOperations(t)
defer cancel()
- om.updater.workQueues = []chan *core.OperationUpdate{
- make(chan *core.OperationUpdate, 1),
+ om.updater.workQueues = []chan *core.OperationUpdateAsync{
+ make(chan *core.OperationUpdateAsync, 1),
}
ctx := context.Background()
@@ -236,8 +236,8 @@ func TestRunOperationFailNonIdempotentInit(t *testing.T) {
om, cancel := newTestOperations(t)
defer cancel()
- om.updater.workQueues = []chan *core.OperationUpdate{
- make(chan *core.OperationUpdate, 1),
+ om.updater.workQueues = []chan *core.OperationUpdateAsync{
+ make(chan *core.OperationUpdateAsync, 1),
}
ctx := context.Background()
@@ -264,8 +264,8 @@ func TestRunOperationFailConflict(t *testing.T) {
om, cancel := newTestOperations(t)
defer cancel()
- om.updater.workQueues = []chan *core.OperationUpdate{
- make(chan *core.OperationUpdate, 1),
+ om.updater.workQueues = []chan *core.OperationUpdateAsync{
+ make(chan *core.OperationUpdateAsync, 1),
}
ctx := context.Background()
@@ -289,8 +289,8 @@ func TestRunOperationFailRemainPending(t *testing.T) {
om, cancel := newTestOperations(t)
defer cancel()
- om.updater.workQueues = []chan *core.OperationUpdate{
- make(chan *core.OperationUpdate),
+ om.updater.workQueues = []chan *core.OperationUpdateAsync{
+ make(chan *core.OperationUpdateAsync),
}
om.updater.cancelFunc()
@@ -742,3 +742,159 @@ func TestErrTernaryHelper(t *testing.T) {
assert.Equal(t, core.OpPhasePending, ErrTernary(nil, core.OpPhaseInitializing, core.OpPhasePending))
assert.Equal(t, core.OpPhaseInitializing, ErrTernary(fmt.Errorf("pop"), core.OpPhaseInitializing, core.OpPhasePending))
}
+
+func TestSubmitBulkOperationUpdates(t *testing.T) {
+ om, cancel := newTestOperations(t)
+ defer cancel()
+
+ ctx := context.Background()
+
+ operations := make([]*core.Operation, 0)
+ opID := fftypes.NewUUID()
+ op := &core.Operation{
+ Namespace: "ns1",
+ ID: opID,
+ Plugin: "blockchain",
+ Type: core.OpTypeBlockchainPinBatch,
+ Status: core.OpStatusInitialized,
+ }
+ op2ID := fftypes.NewUUID()
+ op2 := &core.Operation{
+ Namespace: "ns2",
+ ID: op2ID,
+ Plugin: "blockchain",
+ Type: core.OpTypeBlockchainContractDeploy,
+ Status: core.OpStatusInitialized,
+ }
+ operations = append(operations, op, op2)
+
+ submittedUpdate := &core.OperationUpdate{
+ NamespacedOpID: "ns1:" + opID.String(),
+ Status: core.OpStatusSucceeded,
+ ErrorMessage: "my-error-message",
+ Plugin: "blockchain",
+ }
+
+ submittedUpdate2 := &core.OperationUpdate{
+ NamespacedOpID: "ns1:" + op2ID.String(),
+ Status: core.OpStatusSucceeded,
+ ErrorMessage: "my-error-message",
+ Plugin: "blockchain",
+ }
+
+ mdi := om.database.(*databasemocks.Plugin)
+ mdi.On("GetOperations", ctx, "ns1", mock.Anything).Return(operations, nil, nil)
+
+ mdi.On("UpdateOperation", ctx, "ns1", opID, mock.Anything, mock.Anything).Return(true, nil)
+ mdi.On("UpdateOperation", ctx, "ns2", op2ID, mock.Anything, mock.Anything).Return(true, nil)
+
+ err := om.SubmitBulkOperationUpdates(ctx, []*core.OperationUpdate{submittedUpdate, submittedUpdate2})
+ assert.NoError(t, err)
+}
+
+func TestSubmitBulkOperationUpdatesErrorNoPlugin(t *testing.T) {
+ om, cancel := newTestOperations(t)
+ defer cancel()
+
+ ctx := context.Background()
+
+ operations := make([]*core.Operation, 0)
+ opID := fftypes.NewUUID()
+ op := &core.Operation{
+ ID: opID,
+ Plugin: "blockchain",
+ Type: core.OpTypeBlockchainPinBatch,
+ Status: core.OpStatusInitialized,
+ }
+
+ operations = append(operations, op)
+
+ submittedUpdate := &core.OperationUpdate{
+ NamespacedOpID: "ns1:" + opID.String(),
+ Status: core.OpStatusSucceeded,
+ ErrorMessage: "my-error-message",
+ }
+
+ mdi := om.database.(*databasemocks.Plugin)
+ mdi.On("GetOperations", ctx, "ns1", mock.Anything).Return(operations, nil, nil)
+
+ err := om.SubmitBulkOperationUpdates(ctx, []*core.OperationUpdate{submittedUpdate})
+ assert.Error(t, err)
+ assert.Regexp(t, "FF10479", err.Error())
+}
+
+func TestSubmitBulkOperationUpdatesErrorWrongNamespace(t *testing.T) {
+ om, cancel := newTestOperations(t)
+ defer cancel()
+
+ ctx := context.Background()
+
+ operations := make([]*core.Operation, 0)
+ opID := fftypes.NewUUID()
+ op := &core.Operation{
+ ID: opID,
+ Plugin: "blockchain",
+ Type: core.OpTypeBlockchainPinBatch,
+ Status: core.OpStatusInitialized,
+ }
+ operations = append(operations, op)
+
+ submittedUpdate := &core.OperationUpdate{
+ NamespacedOpID: "different-namespace:" + opID.String(),
+ Status: core.OpStatusSucceeded,
+ ErrorMessage: "my-error-message",
+ Plugin: "blockchain",
+ }
+
+ err := om.SubmitBulkOperationUpdates(ctx, []*core.OperationUpdate{submittedUpdate})
+ assert.Error(t, err)
+ assert.Regexp(t, "FF10478", err.Error())
+}
+
+func TestSubmitBulkOperationUpdatesIgnoredBadID(t *testing.T) {
+ om, cancel := newTestOperations(t)
+ defer cancel()
+
+ ctx := context.Background()
+
+ submittedUpdate := &core.OperationUpdate{
+ NamespacedOpID: "ns1:BAD-UUID",
+ Status: core.OpStatusSucceeded,
+ ErrorMessage: "my-error-message",
+ Plugin: "blockchain",
+ }
+
+ err := om.SubmitBulkOperationUpdates(ctx, []*core.OperationUpdate{submittedUpdate})
+ assert.Error(t, err)
+ assert.Regexp(t, "FF00138", err.Error())
+}
+
+func TestSubmitBulkOperationUpdatesError(t *testing.T) {
+ om, cancel := newTestOperations(t)
+ defer cancel()
+
+ ctx := context.Background()
+
+ operations := make([]*core.Operation, 0)
+ opID := fftypes.NewUUID()
+ op := &core.Operation{
+ ID: opID,
+ Plugin: "blockchain",
+ Type: core.OpTypeBlockchainPinBatch,
+ Status: core.OpStatusInitialized,
+ }
+ operations = append(operations, op)
+
+ submittedUpdate := &core.OperationUpdate{
+ NamespacedOpID: "ns1:" + opID.String(),
+ Status: core.OpStatusSucceeded,
+ ErrorMessage: "my-error-message",
+ Plugin: "blockchain",
+ }
+
+ mdi := om.database.(*databasemocks.Plugin)
+ mdi.On("GetOperations", ctx, "ns1", mock.Anything).Return(operations, nil, errors.New("Failed to get operations"))
+
+ err := om.SubmitBulkOperationUpdates(ctx, []*core.OperationUpdate{submittedUpdate})
+ assert.Error(t, err)
+}
diff --git a/internal/operations/operation_updater.go b/internal/operations/operation_updater.go
index 9f3b6d3a6f..0def75ea2d 100644
--- a/internal/operations/operation_updater.go
+++ b/internal/operations/operation_updater.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2023 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -35,7 +35,7 @@ import (
)
type operationUpdaterBatch struct {
- updates []*core.OperationUpdate
+ updates []*core.OperationUpdateAsync
timeoutContext context.Context
timeoutCancel func()
}
@@ -47,7 +47,7 @@ type operationUpdater struct {
manager *operationsManager
database database.Plugin
txHelper txcommon.Helper
- workQueues []chan *core.OperationUpdate
+ workQueues []chan *core.OperationUpdateAsync
workersDone []chan struct{}
conf operationUpdaterConf
closed bool
@@ -87,13 +87,49 @@ func newOperationUpdater(ctx context.Context, om *operationsManager, di database
}
// pickWorker ensures multiple updates for the same ID go to the same worker
-func (ou *operationUpdater) pickWorker(ctx context.Context, id *fftypes.UUID, update *core.OperationUpdate) chan *core.OperationUpdate {
+func (ou *operationUpdater) pickWorker(ctx context.Context, id *fftypes.UUID, update *core.OperationUpdateAsync) chan *core.OperationUpdateAsync {
worker := id.HashBucket(ou.conf.workerCount)
log.L(ctx).Debugf("Submitting operation update id=%s status=%s blockchainTX=%s worker=opu_%.3d", id, update.Status, update.BlockchainTXID, worker)
return ou.workQueues[worker]
}
-func (ou *operationUpdater) SubmitOperationUpdate(ctx context.Context, update *core.OperationUpdate) {
+// SubmitBulkOperationUpdates is a synchronous write of batch of operation updates
+func (ou *operationUpdater) SubmitBulkOperationUpdates(ctx context.Context, updates []*core.OperationUpdate) error {
+ validUpdates := []*core.OperationUpdate{}
+ for _, update := range updates {
+ ns, _, err := core.ParseNamespacedOpID(ctx, update.NamespacedOpID)
+ if err != nil {
+ log.L(ctx).Warnf("Unable to update operation '%s' due to invalid ID: %s", update.NamespacedOpID, err)
+ return err
+ }
+
+ if ns != ou.manager.namespace {
+ log.L(ou.ctx).Errorf("Received operation update from different namespace '%s'", ns)
+ return i18n.NewError(ctx, coremsgs.MsgInvalidNamespaceForOperationUpdate, ns, ou.manager.namespace)
+ }
+
+ if update.Plugin == "" {
+ log.L(ou.ctx).Errorf("Cannot supply empty plugin on operation update '%s'", update.NamespacedOpID)
+ return i18n.NewError(ctx, coremsgs.MsgEmptyPluginForOperationUpdate, update.NamespacedOpID)
+ }
+
+ validUpdates = append(validUpdates, update)
+ }
+
+ // Notice how this is not using the workers and is synchronous
+ // The reason is because we want for all updates to be stored at once in this order
+ // If offloaded into workers the updates would be processed in parallel, in different DB TX and in a different order
+ // Up to the caller to retry if this fails
+ err := ou.doBatchUpdateAsGroup(ctx, validUpdates)
+ if err != nil {
+ log.L(ctx).Warnf("Exiting while updating operations: %s", err)
+ return err
+ }
+
+ return nil
+}
+
+func (ou *operationUpdater) SubmitOperationUpdate(ctx context.Context, update *core.OperationUpdateAsync) {
ns, id, err := core.ParseNamespacedOpID(ctx, update.NamespacedOpID)
if err != nil {
log.L(ctx).Warnf("Unable to update operation '%s' due to invalid ID: %s", update.NamespacedOpID, err)
@@ -119,17 +155,17 @@ func (ou *operationUpdater) SubmitOperationUpdate(ctx context.Context, update *c
return
}
// Otherwise do it in-line on this context
- err = ou.doBatchUpdateWithRetry(ctx, []*core.OperationUpdate{update})
+ err = ou.doBatchUpdateWithRetry(ctx, []*core.OperationUpdateAsync{update})
if err != nil {
log.L(ctx).Warnf("Exiting while updating operation: %s", err)
}
}
func (ou *operationUpdater) initQueues() {
- ou.workQueues = make([]chan *core.OperationUpdate, ou.conf.workerCount)
+ ou.workQueues = make([]chan *core.OperationUpdateAsync, ou.conf.workerCount)
ou.workersDone = make([]chan struct{}, ou.conf.workerCount)
for i := 0; i < ou.conf.workerCount; i++ {
- ou.workQueues[i] = make(chan *core.OperationUpdate, ou.conf.queueLength)
+ ou.workQueues[i] = make(chan *core.OperationUpdateAsync, ou.conf.queueLength)
ou.workersDone[i] = make(chan struct{})
}
}
@@ -181,14 +217,23 @@ func (ou *operationUpdater) updaterLoop(index int) {
}
}
-func (ou *operationUpdater) doBatchUpdateWithRetry(ctx context.Context, updates []*core.OperationUpdate) error {
+func (ou *operationUpdater) doBatchUpdateAsGroup(ctx context.Context, updates []*core.OperationUpdate) error {
+ return ou.database.RunAsGroup(ctx, func(ctx context.Context) error {
+ return ou.doBatchUpdate(ctx, updates)
+ })
+}
+
+func (ou *operationUpdater) doBatchUpdateWithRetry(ctx context.Context, updates []*core.OperationUpdateAsync) error {
return ou.retry.Do(ctx, "operation update", func(attempt int) (retry bool, err error) {
- err = ou.database.RunAsGroup(ctx, func(ctx context.Context) error {
- return ou.doBatchUpdate(ctx, updates)
- })
+ syncUpdates := []*core.OperationUpdate{}
+ for _, update := range updates {
+ syncUpdates = append(syncUpdates, &update.OperationUpdate)
+ }
+ err = ou.doBatchUpdateAsGroup(ctx, syncUpdates)
if err != nil {
return true, err
}
+
for _, update := range updates {
if update.OnComplete != nil {
update.OnComplete()
@@ -199,7 +244,6 @@ func (ou *operationUpdater) doBatchUpdateWithRetry(ctx context.Context, updates
}
func (ou *operationUpdater) doBatchUpdate(ctx context.Context, updates []*core.OperationUpdate) error {
-
// Get all the operations that match
opIDs := make([]*fftypes.UUID, 0, len(updates))
for _, update := range updates {
diff --git a/internal/operations/operation_updater_test.go b/internal/operations/operation_updater_test.go
index 6d31db81a7..6a4fd97c57 100644
--- a/internal/operations/operation_updater_test.go
+++ b/internal/operations/operation_updater_test.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2021 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -105,24 +105,28 @@ func TestNewOperationUpdaterNoConcurrency(t *testing.T) {
func TestSubmitUpdateBadIDIgnored(t *testing.T) {
ou := newTestOperationUpdater(t)
ou.close()
- ou.workQueues = []chan *core.OperationUpdate{
- make(chan *core.OperationUpdate),
+ ou.workQueues = []chan *core.OperationUpdateAsync{
+ make(chan *core.OperationUpdateAsync),
}
ou.cancelFunc()
- ou.SubmitOperationUpdate(ou.ctx, &core.OperationUpdate{
- NamespacedOpID: "!!!" + fftypes.NewUUID().String(),
+ ou.SubmitOperationUpdate(ou.ctx, &core.OperationUpdateAsync{
+ OperationUpdate: core.OperationUpdate{
+ NamespacedOpID: "!!!" + fftypes.NewUUID().String(),
+ },
})
}
func TestSubmitUpdateClosed(t *testing.T) {
ou := newTestOperationUpdater(t)
ou.close()
- ou.workQueues = []chan *core.OperationUpdate{
- make(chan *core.OperationUpdate),
+ ou.workQueues = []chan *core.OperationUpdateAsync{
+ make(chan *core.OperationUpdateAsync),
}
ou.cancelFunc()
- ou.SubmitOperationUpdate(ou.ctx, &core.OperationUpdate{
- NamespacedOpID: "ns1:" + fftypes.NewUUID().String(),
+ ou.SubmitOperationUpdate(ou.ctx, &core.OperationUpdateAsync{
+ OperationUpdate: core.OperationUpdate{
+ NamespacedOpID: "ns1:" + fftypes.NewUUID().String(),
+ },
})
}
@@ -139,9 +143,11 @@ func TestSubmitUpdateSyncFallbackOpNotFound(t *testing.T) {
mdi.On("GetOperations", customCtx, mock.Anything, mock.Anything).Return(nil, nil, nil)
complete := false
- ou.SubmitOperationUpdate(customCtx, &core.OperationUpdate{
- NamespacedOpID: "ns1:" + fftypes.NewUUID().String(),
- OnComplete: func() { complete = true },
+ ou.SubmitOperationUpdate(customCtx, &core.OperationUpdateAsync{
+ OperationUpdate: core.OperationUpdate{
+ NamespacedOpID: "ns1:" + fftypes.NewUUID().String(),
+ },
+ OnComplete: func() { complete = true },
})
assert.True(t, complete)
@@ -158,8 +164,10 @@ func TestSubmitUpdateDatabaseError(t *testing.T) {
mdi := ou.database.(*databasemocks.Plugin)
mdi.On("RunAsGroup", mock.Anything, mock.Anything).Return(fmt.Errorf("pop"))
- ou.SubmitOperationUpdate(ctx, &core.OperationUpdate{
- NamespacedOpID: "ns1:" + fftypes.NewUUID().String(),
+ ou.SubmitOperationUpdate(ctx, &core.OperationUpdateAsync{
+ OperationUpdate: core.OperationUpdate{
+ NamespacedOpID: "ns1:" + fftypes.NewUUID().String(),
+ },
})
mdi.AssertExpectations(t)
@@ -170,8 +178,10 @@ func TestSubmitUpdateWrongNS(t *testing.T) {
defer ou.close()
customCtx := context.WithValue(context.Background(), "dbtx", "on this context")
- ou.SubmitOperationUpdate(customCtx, &core.OperationUpdate{
- NamespacedOpID: "ns2:" + fftypes.NewUUID().String(),
+ ou.SubmitOperationUpdate(customCtx, &core.OperationUpdateAsync{
+ OperationUpdate: core.OperationUpdate{
+ NamespacedOpID: "ns2:" + fftypes.NewUUID().String(),
+ },
})
}
@@ -218,21 +228,27 @@ func TestSubmitUpdateWorkerE2ESuccess(t *testing.T) {
}).Once()
om.Start()
- om.SubmitOperationUpdate(&core.OperationUpdate{
- NamespacedOpID: "ns1:" + opID1.String(),
- Status: core.OpStatusSucceeded,
- BlockchainTXID: "tx12345",
+ om.SubmitOperationUpdate(&core.OperationUpdateAsync{
+ OperationUpdate: core.OperationUpdate{
+ NamespacedOpID: "ns1:" + opID1.String(),
+ Status: core.OpStatusSucceeded,
+ BlockchainTXID: "tx12345",
+ },
})
- om.SubmitOperationUpdate(&core.OperationUpdate{
- NamespacedOpID: "ns1:" + opID2.String(),
- Status: core.OpStatusFailed,
- ErrorMessage: "err1",
- Output: fftypes.JSONObject{"test": true},
+ om.SubmitOperationUpdate(&core.OperationUpdateAsync{
+ OperationUpdate: core.OperationUpdate{
+ NamespacedOpID: "ns1:" + opID2.String(),
+ Status: core.OpStatusFailed,
+ ErrorMessage: "err1",
+ Output: fftypes.JSONObject{"test": true},
+ },
})
- om.SubmitOperationUpdate(&core.OperationUpdate{
- NamespacedOpID: "ns1:" + opID3.String(),
- Status: core.OpStatusFailed,
- ErrorMessage: "err2",
+ om.SubmitOperationUpdate(&core.OperationUpdateAsync{
+ OperationUpdate: core.OperationUpdate{
+ NamespacedOpID: "ns1:" + opID3.String(),
+ Status: core.OpStatusFailed,
+ ErrorMessage: "err2",
+ },
})
<-done
@@ -250,8 +266,10 @@ func TestUpdateLoopExitRetryCancelledContext(t *testing.T) {
ou.cancelFunc()
})
- ou.SubmitOperationUpdate(ou.ctx, &core.OperationUpdate{
- NamespacedOpID: "ns1:" + fftypes.NewUUID().String(),
+ ou.SubmitOperationUpdate(ou.ctx, &core.OperationUpdateAsync{
+ OperationUpdate: core.OperationUpdate{
+ NamespacedOpID: "ns1:" + fftypes.NewUUID().String(),
+ },
})
ou.updaterLoop(0)
diff --git a/internal/orchestrator/bound_callbacks.go b/internal/orchestrator/bound_callbacks.go
index 5fc3c3df79..f9d2d2cc64 100644
--- a/internal/orchestrator/bound_callbacks.go
+++ b/internal/orchestrator/bound_callbacks.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2023 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -20,6 +20,8 @@ import (
"context"
"sync"
+ "github.com/hyperledger/firefly-common/pkg/log"
+
"github.com/hyperledger/firefly-common/pkg/fftypes"
"github.com/hyperledger/firefly-common/pkg/i18n"
"github.com/hyperledger/firefly/internal/coremsgs"
@@ -41,7 +43,11 @@ func (bc *boundCallbacks) checkStopped() error {
return nil
}
-func (bc *boundCallbacks) OperationUpdate(update *core.OperationUpdate) {
+func (bc *boundCallbacks) BulkOperationUpdates(ctx context.Context, updates []*core.OperationUpdate) error {
+ return bc.o.operations.SubmitBulkOperationUpdates(ctx, updates)
+}
+
+func (bc *boundCallbacks) OperationUpdate(update *core.OperationUpdateAsync) {
bc.o.operations.SubmitOperationUpdate(update)
}
@@ -93,3 +99,13 @@ func (bc *boundCallbacks) TokensApproved(plugin tokens.Plugin, approval *tokens.
}
return bc.o.events.TokensApproved(plugin, approval)
}
+
+func (bc *boundCallbacks) DXConnect(plugin dataexchange.Plugin) {
+ err := bc.checkStopped()
+ if err == nil {
+ err = bc.o.networkmap.CheckNodeIdentityStatus(bc.o.ctx)
+ }
+ if err != nil {
+ log.L(bc.o.ctx).Errorf("Error handling DX connect callback: %s", err)
+ }
+}
diff --git a/internal/orchestrator/bound_callbacks_test.go b/internal/orchestrator/bound_callbacks_test.go
index 06bd633831..ddc728f5ab 100644
--- a/internal/orchestrator/bound_callbacks_test.go
+++ b/internal/orchestrator/bound_callbacks_test.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2021 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -21,6 +21,8 @@ import (
"fmt"
"testing"
+ "github.com/hyperledger/firefly/mocks/networkmapmocks"
+
"github.com/hyperledger/firefly-common/pkg/fftypes"
"github.com/hyperledger/firefly/mocks/dataexchangemocks"
"github.com/hyperledger/firefly/mocks/eventmocks"
@@ -34,17 +36,19 @@ import (
"github.com/stretchr/testify/mock"
)
-func newTestBoundCallbacks(t *testing.T) (*eventmocks.EventManager, *sharedstoragemocks.Plugin, *operationmocks.Manager, *boundCallbacks) {
+func newTestBoundCallbacks(t *testing.T) (*eventmocks.EventManager, *sharedstoragemocks.Plugin, *operationmocks.Manager, *networkmapmocks.Manager, *boundCallbacks) {
mei := &eventmocks.EventManager{}
mss := &sharedstoragemocks.Plugin{}
mom := &operationmocks.Manager{}
+ mnm := &networkmapmocks.Manager{}
bc := &boundCallbacks{
o: &orchestrator{
- ctx: context.Background(),
- namespace: &core.Namespace{Name: "ns1"},
- started: true,
- events: mei,
+ ctx: context.Background(),
+ namespace: &core.Namespace{Name: "ns1"},
+ networkmap: mnm,
+ started: true,
+ events: mei,
plugins: &Plugins{
SharedStorage: SharedStoragePlugin{
Plugin: mss,
@@ -53,12 +57,12 @@ func newTestBoundCallbacks(t *testing.T) (*eventmocks.EventManager, *sharedstora
operations: mom,
},
}
- return mei, mss, mom, bc
+ return mei, mss, mom, mnm, bc
}
func TestBoundCallbacks(t *testing.T) {
- mei, mss, mom, bc := newTestBoundCallbacks(t)
+ mei, mss, mom, mnm, bc := newTestBoundCallbacks(t)
mdx := &dataexchangemocks.Plugin{}
mti := &tokenmocks.Plugin{}
@@ -68,15 +72,23 @@ func TestBoundCallbacks(t *testing.T) {
nsOpID := "ns1:" + opID.String()
dataID := fftypes.NewUUID()
- update := &core.OperationUpdate{
+ operationUpdate := &core.OperationUpdate{
NamespacedOpID: nsOpID,
Status: core.OpStatusFailed,
BlockchainTXID: "0xffffeeee",
ErrorMessage: "error info",
Output: info,
}
- mom.On("SubmitOperationUpdate", update).Return().Once()
- bc.OperationUpdate(update)
+ operationUpdateAsync := &core.OperationUpdateAsync{
+ OperationUpdate: *operationUpdate,
+ }
+ mom.On("SubmitOperationUpdate", operationUpdateAsync).Return().Once()
+ bc.OperationUpdate(operationUpdateAsync)
+
+ ctx := context.Background()
+ updates := []*core.OperationUpdate{operationUpdate}
+ mom.On("SubmitBulkOperationUpdates", ctx, updates).Return(nil).Once()
+ bc.BulkOperationUpdates(ctx, updates)
mei.On("SharedStorageBatchDownloaded", mss, "payload1", []byte(`{}`)).Return(nil, fmt.Errorf("pop"))
_, err := bc.SharedStorageBatchDownloaded("payload1", []byte(`{}`))
@@ -94,6 +106,10 @@ func TestBoundCallbacks(t *testing.T) {
err = bc.DXEvent(mdx, &dataexchangemocks.DXEvent{})
assert.NoError(t, err)
+ mnm.On("CheckNodeIdentityStatus", mock.Anything, mock.Anything).Return(nil)
+ bc.DXConnect(mdx)
+ assert.NoError(t, err)
+
mei.On("TokenPoolCreated", mock.Anything, mti, &tokens.TokenPool{}).Return(nil)
err = bc.TokenPoolCreated(context.Background(), mti, &tokens.TokenPool{})
assert.NoError(t, err)
@@ -109,11 +125,12 @@ func TestBoundCallbacks(t *testing.T) {
mei.AssertExpectations(t)
mss.AssertExpectations(t)
mom.AssertExpectations(t)
+ mnm.AssertExpectations(t)
}
func TestBoundCallbacksStopped(t *testing.T) {
- _, _, _, bc := newTestBoundCallbacks(t)
+ _, _, _, _, bc := newTestBoundCallbacks(t)
bc.o.started = false
_, err := bc.SharedStorageBatchDownloaded("payload1", []byte(`{}`))
@@ -128,6 +145,9 @@ func TestBoundCallbacksStopped(t *testing.T) {
err = bc.DXEvent(nil, &dataexchangemocks.DXEvent{})
assert.Regexp(t, "FF10446", err)
+ bc.DXConnect(nil)
+ // no-op
+
err = bc.TokenPoolCreated(context.Background(), nil, &tokens.TokenPool{})
assert.Regexp(t, "FF10446", err)
diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go
index 5909aeaa87..40d6e0a85c 100644
--- a/internal/orchestrator/orchestrator.go
+++ b/internal/orchestrator/orchestrator.go
@@ -304,6 +304,13 @@ func (or *orchestrator) Start() (err error) {
}
or.started = true
+
+ if or.config.Multiparty.Enabled {
+ err := or.networkmap.CheckNodeIdentityStatus(or.ctx)
+ if err != nil {
+ log.L(or.ctx).Errorf("Error checking node identity status: %s", err.Error())
+ }
+ }
return err
}
diff --git a/internal/orchestrator/orchestrator_test.go b/internal/orchestrator/orchestrator_test.go
index 6c2cc85e67..1a328a0ecf 100644
--- a/internal/orchestrator/orchestrator_test.go
+++ b/internal/orchestrator/orchestrator_test.go
@@ -459,6 +459,7 @@ func TestStartBatchFail(t *testing.T) {
defer or.cleanup(t)
or.mdm.On("Start").Return(nil)
or.mba.On("Start").Return(fmt.Errorf("pop"))
+ or.mnm.On("CheckNodeIdentityStatus", or.ctx).Return(nil)
err := or.Start()
assert.EqualError(t, err, "pop")
}
@@ -482,6 +483,7 @@ func TestStartStopOk(t *testing.T) {
or.mem.On("Start").Return(nil)
or.mbm.On("Start").Return(nil)
or.msd.On("Start").Return(nil)
+ or.mnm.On("CheckNodeIdentityStatus", or.ctx).Return(nil)
or.mom.On("Start").Return(nil)
or.mtw.On("Start").Return()
or.mam.On("Start").Return(nil)
@@ -505,6 +507,7 @@ func TestStartStopOk(t *testing.T) {
or.mem.On("Start").Return(nil)
or.mbm.On("Start").Return(nil)
or.msd.On("Start").Return(nil)
+ or.mnm.On("CheckNodeIdentityStatus", or.ctx).Return(errors.New("benign error"))
or.mom.On("Start").Return(nil)
or.mtw.On("Start").Return()
or.mam.On("Start").Return(nil)
diff --git a/internal/orchestrator/subscriptions.go b/internal/orchestrator/subscriptions.go
index d7ebe97435..c0f9dadae7 100644
--- a/internal/orchestrator/subscriptions.go
+++ b/internal/orchestrator/subscriptions.go
@@ -180,9 +180,14 @@ func (or *orchestrator) GetSubscriptionEventsHistorical(ctx context.Context, sub
return nil, nil, err
}
+ intLimit := len(filteredEvents)
+ if requestedFiltering.Limit < uint64(intLimit) {
+ //nolint:gosec
+ intLimit = int(requestedFiltering.Limit)
+ }
var filteredEventsMatchingSubscription []*core.EnrichedEvent
- if len(filteredEvents) > int(requestedFiltering.Limit) {
- filteredEventsMatchingSubscription = filteredEvents[len(filteredEvents)-int(requestedFiltering.Limit):]
+ if len(filteredEvents) > intLimit {
+ filteredEventsMatchingSubscription = filteredEvents[len(filteredEvents)-intLimit:]
} else {
filteredEventsMatchingSubscription = filteredEvents
}
diff --git a/internal/privatemessaging/operations.go b/internal/privatemessaging/operations.go
index 5a6ef8c0f4..c37638ccb7 100644
--- a/internal/privatemessaging/operations.go
+++ b/internal/privatemessaging/operations.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2023 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -130,6 +130,7 @@ func (pm *privateMessaging) PrepareOperation(ctx context.Context, op *core.Opera
return nil, err
}
transport := &core.TransportWrapper{Group: group, Batch: batch}
+ pm.prepareBatchForNetworkTransport(ctx, transport)
return opSendBatch(op, node, transport), nil
default:
diff --git a/internal/privatemessaging/operations_test.go b/internal/privatemessaging/operations_test.go
index 8b1ad8df84..212915c786 100644
--- a/internal/privatemessaging/operations_test.go
+++ b/internal/privatemessaging/operations_test.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2022 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -149,6 +149,7 @@ func TestPrepareAndRunBatchSend(t *testing.T) {
assert.Equal(t, node, po.Data.(batchSendData).Node)
assert.Equal(t, group, po.Data.(batchSendData).Transport.Group)
assert.Equal(t, batch, po.Data.(batchSendData).Transport.Batch)
+ assert.Equal(t, "ns1-remote", po.Data.(batchSendData).Transport.Batch.Namespace) // ensure its set to the network name not the local namespace name
_, phase, err := pm.RunOperation(context.Background(), po)
diff --git a/internal/privatemessaging/privatemessaging.go b/internal/privatemessaging/privatemessaging.go
index d38d163900..886eafa11c 100644
--- a/internal/privatemessaging/privatemessaging.go
+++ b/internal/privatemessaging/privatemessaging.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2024 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -130,7 +130,7 @@ func NewPrivateMessaging(ctx context.Context, ns *core.Namespace, di database.Pl
bo := batch.DispatcherOptions{
BatchType: core.BatchTypePrivate,
- BatchMaxSize: config.GetUint(coreconfig.PrivateMessagingBatchSize),
+ BatchMaxSize: config.GetInt(coreconfig.PrivateMessagingBatchSize),
BatchMaxBytes: pm.maxBatchPayloadLength,
BatchTimeout: config.GetDuration(coreconfig.PrivateMessagingBatchTimeout),
DisposeTimeout: config.GetDuration(coreconfig.PrivateMessagingBatchAgentTimeout),
@@ -179,12 +179,20 @@ func (pm *privateMessaging) dispatchUnpinnedBatch(ctx context.Context, payload *
return pm.dispatchBatchCommon(ctx, payload)
}
+// prepareBatchForNetworkTransport is mainly for documentation purposes, we need to "normalize" a batch before sending
+// it over the network to other parties, so that all nodes see the same batch, regardless of what they call their local
+// namespace. This is used when we dispatch a batch per the regular messaging flow, and when we retry a private messaging
+// send operation.
+func (pm *privateMessaging) prepareBatchForNetworkTransport(ctx context.Context, tw *core.TransportWrapper) {
+ tw.Batch.Namespace = pm.namespace.NetworkName
+}
+
func (pm *privateMessaging) dispatchBatchCommon(ctx context.Context, payload *batch.DispatchPayload) error {
batch := payload.Batch.GenInflight(payload.Messages, payload.Data)
- batch.Namespace = pm.namespace.NetworkName
tw := &core.TransportWrapper{
Batch: batch,
}
+ pm.prepareBatchForNetworkTransport(ctx, tw)
// Retrieve the group
group, nodes, err := pm.groupManager.getGroupNodes(ctx, batch.Group, false /* fail if not found */)
diff --git a/internal/privatemessaging/privatemessaging_test.go b/internal/privatemessaging/privatemessaging_test.go
index dab7daccd7..6606c3f220 100644
--- a/internal/privatemessaging/privatemessaging_test.go
+++ b/internal/privatemessaging/privatemessaging_test.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2021 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -84,7 +84,7 @@ func newTestPrivateMessagingCommon(t *testing.T, metricsEnabled bool) (*privateM
mmi.On("IsMetricsEnabled").Return(metricsEnabled)
mom.On("RegisterHandler", mock.Anything, mock.Anything, mock.Anything)
- ns := &core.Namespace{Name: "ns1", NetworkName: "ns1"}
+ ns := &core.Namespace{Name: "ns1", NetworkName: "ns1-remote"}
pm, err := NewPrivateMessaging(ctx, ns, mdi, mdx, mbi, mim, mba, mdm, msa, mmp, mmi, mom, cmi)
assert.NoError(t, err)
cmi.AssertCalled(t, "GetCache", cache.NewCacheConfig(
diff --git a/internal/privatemessaging/recipients_test.go b/internal/privatemessaging/recipients_test.go
index d8d97af30d..c6407466c2 100644
--- a/internal/privatemessaging/recipients_test.go
+++ b/internal/privatemessaging/recipients_test.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2021 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -85,7 +85,7 @@ func TestResolveMemberListNewGroupE2E(t *testing.T) {
um.RunFn = func(a mock.Arguments) {
msg := a[1].(*core.Message)
assert.Equal(t, core.MessageTypeGroupInit, msg.Header.Type)
- assert.Equal(t, "ns1", msg.Header.Namespace)
+ assert.Equal(t, "ns1-remote", msg.Header.Namespace) // note this matches the remote network name, not the local namespace
assert.Len(t, msg.Data, 1)
assert.Equal(t, *dataID, *msg.Data[0].ID)
}
diff --git a/internal/reference/reference.go b/internal/reference/reference.go
index 699c6aab1b..1befee9cd3 100644
--- a/internal/reference/reference.go
+++ b/internal/reference/reference.go
@@ -50,7 +50,7 @@ type TypeReferenceDoc struct {
func GenerateObjectsReferenceMarkdown(ctx context.Context) (map[string][]byte, error) {
newest := core.SubOptsFirstEventNewest
- fifty := uint16(50)
+ fifty := uint(50)
falseVar := false
types := []interface{}{
@@ -790,14 +790,14 @@ func generateObjectReferenceMarkdown(ctx context.Context, descRequired bool, exa
if typeReferenceDoc.Description != nil {
buff.Write(typeReferenceDoc.Description)
}
- if typeReferenceDoc.Example != nil && len(typeReferenceDoc.Example) > 0 {
+ if len(typeReferenceDoc.Example) > 0 {
if sectionCount > 1 {
buff.WriteString("### Example\n\n```json\n")
}
buff.Write(typeReferenceDoc.Example)
buff.WriteString("\n```\n\n")
}
- if typeReferenceDoc.FieldDescriptions != nil && len(typeReferenceDoc.FieldDescriptions) > 0 {
+ if len(typeReferenceDoc.FieldDescriptions) > 0 {
if sectionCount > 1 {
buff.WriteString("### Field Descriptions\n\n")
}
@@ -805,7 +805,7 @@ func generateObjectReferenceMarkdown(ctx context.Context, descRequired bool, exa
buff.WriteString("\n")
}
- if typeReferenceDoc.SubFieldTables != nil && len(typeReferenceDoc.SubFieldTables) > 0 {
+ if len(typeReferenceDoc.SubFieldTables) > 0 {
buff.Write(typeReferenceDoc.SubFieldTables)
}
diff --git a/internal/shareddownload/download_worker.go b/internal/shareddownload/download_worker.go
index cae26e501c..68409aa9fe 100644
--- a/internal/shareddownload/download_worker.go
+++ b/internal/shareddownload/download_worker.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2023 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -63,11 +63,13 @@ func (dw *downloadWorker) attemptWork(work *downloadWork) {
if err != nil {
log.L(dw.ctx).Errorf("Download operation %s/%s attempt=%d/%d failed: %s", work.preparedOp.Type, work.preparedOp.ID, work.attempts, dw.dm.retryMaxAttempts, err)
if isLastAttempt {
- dw.dm.operations.SubmitOperationUpdate(&core.OperationUpdate{
- NamespacedOpID: work.preparedOp.NamespacedIDString(),
- Plugin: work.preparedOp.Plugin,
- Status: core.OpStatusFailed,
- ErrorMessage: err.Error(),
+ dw.dm.operations.SubmitOperationUpdate(&core.OperationUpdateAsync{
+ OperationUpdate: core.OperationUpdate{
+ NamespacedOpID: work.preparedOp.NamespacedIDString(),
+ Plugin: work.preparedOp.Plugin,
+ Status: core.OpStatusFailed,
+ ErrorMessage: err.Error(),
+ },
})
} else {
go dw.dm.waitAndRetryDownload(work)
diff --git a/internal/syncasync/sync_async_bridge.go b/internal/syncasync/sync_async_bridge.go
index 6328ab9c25..6b7f31b20c 100644
--- a/internal/syncasync/sync_async_bridge.go
+++ b/internal/syncasync/sync_async_bridge.go
@@ -19,7 +19,7 @@ package syncasync
import (
"context"
"encoding/json"
- "fmt"
+ "errors"
"sync"
"time"
@@ -615,7 +615,7 @@ func (sa *syncAsyncBridge) resolveSuccessfulOperation(inflight *inflightRequest,
func (sa *syncAsyncBridge) resolveFailedOperation(inflight *inflightRequest, typeName string, op *core.Operation) {
log.L(sa.ctx).Debugf("Resolving %s request '%s' with error '%s'", typeName, inflight.id, op.Error)
- inflight.response <- inflightResponse{err: fmt.Errorf(op.Error)}
+ inflight.response <- inflightResponse{err: errors.New(op.Error)}
}
func (sa *syncAsyncBridge) sendAndWait(ctx context.Context, ns string, id *fftypes.UUID, reqType requestType, send SendFunction) (interface{}, error) {
diff --git a/internal/tokens/fftokens/fftokens.go b/internal/tokens/fftokens/fftokens.go
index 2f07077b2a..dd959c6cef 100644
--- a/internal/tokens/fftokens/fftokens.go
+++ b/internal/tokens/fftokens/fftokens.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2024 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -74,13 +74,15 @@ type callbacks struct {
func (cb *callbacks) OperationUpdate(ctx context.Context, nsOpID string, status core.OpStatus, blockchainTXID, errorMessage string, opOutput fftypes.JSONObject) {
namespace, _, _ := core.ParseNamespacedOpID(ctx, nsOpID)
if handler, ok := cb.opHandlers[namespace]; ok {
- handler.OperationUpdate(&core.OperationUpdate{
- Plugin: cb.plugin.Name(),
- NamespacedOpID: nsOpID,
- Status: status,
- BlockchainTXID: blockchainTXID,
- ErrorMessage: errorMessage,
- Output: opOutput,
+ handler.OperationUpdate(&core.OperationUpdateAsync{
+ OperationUpdate: core.OperationUpdate{
+ Plugin: cb.plugin.Name(),
+ NamespacedOpID: nsOpID,
+ Status: status,
+ BlockchainTXID: blockchainTXID,
+ ErrorMessage: errorMessage,
+ Output: opOutput,
+ },
})
} else {
log.L(ctx).Errorf("No handler found for token operation '%s'", nsOpID)
@@ -804,7 +806,7 @@ func (ft *FFTokens) CreateTokenPool(ctx context.Context, nsOpID string, pool *co
if err != nil || !res.IsSuccess() {
return core.OpPhaseInitializing, wrapError(ctx, &errRes, res, err)
}
- if res.StatusCode() == 200 {
+ if res.StatusCode() == http.StatusOK {
// HTTP 200: Creation was successful, and pool details are in response body
var obj fftypes.JSONObject
if err := json.Unmarshal(res.Body(), &obj); err != nil {
@@ -839,7 +841,7 @@ func (ft *FFTokens) ActivateTokenPool(ctx context.Context, pool *core.TokenPool)
if err != nil || !res.IsSuccess() {
return core.OpPhaseInitializing, err
}
- if res.StatusCode() == 200 {
+ if res.StatusCode() == http.StatusOK {
// HTTP 200: Activation was successful, and pool details are in response body
var obj fftypes.JSONObject
if err := json.Unmarshal(res.Body(), &obj); err != nil {
@@ -849,7 +851,7 @@ func (ft *FFTokens) ActivateTokenPool(ctx context.Context, pool *core.TokenPool)
TX: pool.TX.ID,
TXType: pool.TX.Type,
})
- } else if res.StatusCode() == 204 {
+ } else if res.StatusCode() == http.StatusNoContent {
// HTTP 204: Activation was successful, but pool details are not available
// This will resolve the operation, but connector is responsible for re-delivering pool details on the websocket.
return core.OpPhaseComplete, nil
@@ -869,7 +871,7 @@ func (ft *FFTokens) DeactivateTokenPool(ctx context.Context, pool *core.TokenPoo
}).
SetError(&errRes).
Post("/api/v1/deactivatepool")
- if err == nil && (res.IsSuccess() || res.StatusCode() == 404) {
+ if err == nil && (res.IsSuccess() || res.StatusCode() == http.StatusNotFound) {
return nil
}
return wrapError(ctx, &errRes, res, err)
diff --git a/internal/tokens/fftokens/fftokens_test.go b/internal/tokens/fftokens/fftokens_test.go
index 886e1d80cc..56d693998f 100644
--- a/internal/tokens/fftokens/fftokens_test.go
+++ b/internal/tokens/fftokens/fftokens_test.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2021 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -1032,7 +1032,7 @@ func TestReceiptEvents(t *testing.T) {
mockCalled := make(chan bool)
// receipt: bad ID - passed through
- mcb.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdate) bool {
+ mcb.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdateAsync) bool {
return update.NamespacedOpID == "ns1:wrong" &&
update.Status == core.OpStatusPending &&
update.Plugin == "fftokens"
@@ -1050,7 +1050,7 @@ func TestReceiptEvents(t *testing.T) {
<-mockCalled
// receipt: success
- mcb.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdate) bool {
+ mcb.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdateAsync) bool {
return update.NamespacedOpID == "ns1:"+opID.String() &&
update.Status == core.OpStatusSucceeded &&
update.BlockchainTXID == "0xffffeeee" &&
@@ -1070,7 +1070,7 @@ func TestReceiptEvents(t *testing.T) {
<-mockCalled
// receipt: update
- mcb.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdate) bool {
+ mcb.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdateAsync) bool {
return update.NamespacedOpID == "ns1:"+opID.String() &&
update.Status == core.OpStatusPending &&
update.BlockchainTXID == "0xffffeeee"
@@ -1089,7 +1089,7 @@ func TestReceiptEvents(t *testing.T) {
<-mockCalled
// receipt: failure
- mcb.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdate) bool {
+ mcb.On("OperationUpdate", mock.MatchedBy(func(update *core.OperationUpdateAsync) bool {
return update.NamespacedOpID == "ns1:"+opID.String() &&
update.Status == core.OpStatusFailed &&
update.BlockchainTXID == "0xffffeeee" &&
diff --git a/internal/txcommon/txcommon.go b/internal/txcommon/txcommon.go
index 84c18ceb13..f7560daf72 100644
--- a/internal/txcommon/txcommon.go
+++ b/internal/txcommon/txcommon.go
@@ -146,7 +146,7 @@ func (t *transactionHelper) SubmitNewTransaction(ctx context.Context, txType cor
return tx.ID, nil
}
-// SubmitTransactionBatch is called to do a batch insertion of a set of transactions, and returns an array of the transaction
+// SubmitNewTransactionBatch is called to do a batch insertion of a set of transactions, and returns an array of the transaction
// result. Each is either a transaction, or an idempotency failure. The overall action fails for DB errors other than idempotency.
func (t *transactionHelper) SubmitNewTransactionBatch(ctx context.Context, namespace string, batch []*BatchedTransactionInsert) error {
diff --git a/manifest.json b/manifest.json
index a6285d4da1..edfcd74273 100644
--- a/manifest.json
+++ b/manifest.json
@@ -1,43 +1,43 @@
{
"ethconnect": {
"image": "ghcr.io/hyperledger/firefly-ethconnect",
- "tag": "v3.3.2",
- "sha": "bdbfa05a0bc1610813ba0ef65b2c8f9f7df4a5ead5643a580e3ba5927747c2cf"
+ "tag": "v3.3.3",
+ "sha": "250509a54bbd3251598a807071b388492c0157df02a3b06bfa64e14e791c0633"
},
"evmconnect": {
"image": "ghcr.io/hyperledger/firefly-evmconnect",
- "tag": "v1.3.18",
- "sha": "11a782c778227d198c0bff2fc94ad7e52ceea5a9994728ba05e781541680c32d"
+ "tag": "v1.3.20",
+ "sha": "514ee0e0d3f6054e1f2c46a474c968f18725af5edd4dc6dac85dc104004c1272"
},
"fabconnect": {
"image": "ghcr.io/hyperledger/firefly-fabconnect",
- "tag": "v0.9.21",
- "sha": "394262c5888fb6647a7b8b1f3f8d652e1db941b67e3c68bccfbedfa53c4d874d"
+ "tag": "v0.9.22",
+ "sha": "1984166545d476b9f8ea8eb04120fed406beb936cb95c97a728bbf4585860523"
},
"tezosconnect": {
"image": "ghcr.io/hyperledger/firefly-tezosconnect",
- "tag": "v0.2.7",
- "sha": "cee6ecda8208e24989a6db2c1a2dd1b0defb89363e7728571b8858e794a295be"
+ "tag": "v0.2.8",
+ "sha": "895c0a22b64fbe42ecaf3e017b40b71c8911c4c7032728c778723cbef987b5de"
},
"dataexchange-https": {
"image": "ghcr.io/hyperledger/firefly-dataexchange-https",
- "tag": "v1.3.0",
- "sha": "1e01b0d5fc3cfd95de150d47c09ba419b8ec98345d105a6d67d7bc7101aeea89"
+ "tag": "v1.3.1",
+ "sha": "5688fd57c52588f55230800e2a13743626da6ce4b40eb7ce3dd4578494418479"
},
"tokens-erc1155": {
"image": "ghcr.io/hyperledger/firefly-tokens-erc1155",
- "tag": "v1.3.3",
- "sha": "5efbe76ce2c484d86e9e3cc2cfe3cee85d91ee8712b31dfc592a2de771749e78"
+ "tag": "v1.3.4",
+ "sha": "700d1d0d461b55641ea21e4028456e904a6f652798335ad0e067d7e6ab1438f1"
},
"tokens-erc20-erc721": {
"image": "ghcr.io/hyperledger/firefly-tokens-erc20-erc721",
- "tag": "v1.3.3",
- "sha": "5cfa10432c1cd885f3cbe5934799d692ba7186013e03a6b92bd6aa53ddf4f414"
+ "tag": "v1.3.4",
+ "sha": "d93b55daf9a4404a3d26996cb2dffcc3660b3ef3cbe3b0be5bab03a8f745d952"
},
"signer": {
"image": "ghcr.io/hyperledger/firefly-signer",
- "tag": "v1.1.17",
- "sha": "4391674f66dadb42ef29f3ea0ac62b130bad041675ff25ad3f8c7c0c8eda3854"
+ "tag": "v1.1.20",
+ "sha": "270f3749f8fa4326de08890d667651a80ff3dfe86c05ad5387671ad0d5b17fe9"
},
"build": {
"firefly-builder": {
@@ -51,14 +51,14 @@
"image": "ethereum/solc:0.8.11-alpine"
},
"base": {
- "image": "alpine:3.19"
+ "image": "alpine:3.19.7"
}
},
"ui": {
"tag": "v1.3.1",
- "release": "v1.3.1"
+ "release": "v1.3.1"
},
"cli": {
- "tag": "v1.3.2"
+ "tag": "v1.3.3"
}
}
diff --git a/mocks/apiservermocks/ffi_swagger_gen.go b/mocks/apiservermocks/ffi_swagger_gen.go
index 08a9311f59..8a6beb8f47 100644
--- a/mocks/apiservermocks/ffi_swagger_gen.go
+++ b/mocks/apiservermocks/ffi_swagger_gen.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package apiservermocks
diff --git a/mocks/apiservermocks/server.go b/mocks/apiservermocks/server.go
index 71247dfb95..209e30aabc 100644
--- a/mocks/apiservermocks/server.go
+++ b/mocks/apiservermocks/server.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package apiservermocks
diff --git a/mocks/assetmocks/manager.go b/mocks/assetmocks/manager.go
index 3f2788b224..95390c40f2 100644
--- a/mocks/assetmocks/manager.go
+++ b/mocks/assetmocks/manager.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package assetmocks
diff --git a/mocks/batchmocks/manager.go b/mocks/batchmocks/manager.go
index a8ceb379e8..f0b548261f 100644
--- a/mocks/batchmocks/manager.go
+++ b/mocks/batchmocks/manager.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package batchmocks
diff --git a/mocks/blockchaincommonmocks/firefly_subscriptions.go b/mocks/blockchaincommonmocks/firefly_subscriptions.go
index 835d36edfc..534b555daf 100644
--- a/mocks/blockchaincommonmocks/firefly_subscriptions.go
+++ b/mocks/blockchaincommonmocks/firefly_subscriptions.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package blockchaincommonmocks
diff --git a/mocks/blockchainmocks/callbacks.go b/mocks/blockchainmocks/callbacks.go
index e4cd093a95..581314a026 100644
--- a/mocks/blockchainmocks/callbacks.go
+++ b/mocks/blockchainmocks/callbacks.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package blockchainmocks
diff --git a/mocks/blockchainmocks/plugin.go b/mocks/blockchainmocks/plugin.go
index 1a8cc47286..ed0b41b049 100644
--- a/mocks/blockchainmocks/plugin.go
+++ b/mocks/blockchainmocks/plugin.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package blockchainmocks
diff --git a/mocks/broadcastmocks/manager.go b/mocks/broadcastmocks/manager.go
index 957f64e75d..43f49a9db5 100644
--- a/mocks/broadcastmocks/manager.go
+++ b/mocks/broadcastmocks/manager.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package broadcastmocks
diff --git a/mocks/cachemocks/manager.go b/mocks/cachemocks/manager.go
index ed923f1558..892a94f2e4 100644
--- a/mocks/cachemocks/manager.go
+++ b/mocks/cachemocks/manager.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package cachemocks
diff --git a/mocks/contractmocks/manager.go b/mocks/contractmocks/manager.go
index 06c26e9343..32654a420c 100644
--- a/mocks/contractmocks/manager.go
+++ b/mocks/contractmocks/manager.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package contractmocks
diff --git a/mocks/coremocks/operation_callbacks.go b/mocks/coremocks/operation_callbacks.go
index 0e6acabc5d..7d00fed033 100644
--- a/mocks/coremocks/operation_callbacks.go
+++ b/mocks/coremocks/operation_callbacks.go
@@ -1,8 +1,10 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package coremocks
import (
+ context "context"
+
core "github.com/hyperledger/firefly/pkg/core"
mock "github.com/stretchr/testify/mock"
)
@@ -12,8 +14,26 @@ type OperationCallbacks struct {
mock.Mock
}
+// BulkOperationUpdates provides a mock function with given fields: ctx, updates
+func (_m *OperationCallbacks) BulkOperationUpdates(ctx context.Context, updates []*core.OperationUpdate) error {
+ ret := _m.Called(ctx, updates)
+
+ if len(ret) == 0 {
+ panic("no return value specified for BulkOperationUpdates")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, []*core.OperationUpdate) error); ok {
+ r0 = rf(ctx, updates)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
// OperationUpdate provides a mock function with given fields: update
-func (_m *OperationCallbacks) OperationUpdate(update *core.OperationUpdate) {
+func (_m *OperationCallbacks) OperationUpdate(update *core.OperationUpdateAsync) {
_m.Called(update)
}
diff --git a/mocks/databasemocks/callbacks.go b/mocks/databasemocks/callbacks.go
index 4bb148b577..f225311cfd 100644
--- a/mocks/databasemocks/callbacks.go
+++ b/mocks/databasemocks/callbacks.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package databasemocks
diff --git a/mocks/databasemocks/plugin.go b/mocks/databasemocks/plugin.go
index 75f9abae40..31da62ec00 100644
--- a/mocks/databasemocks/plugin.go
+++ b/mocks/databasemocks/plugin.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package databasemocks
diff --git a/mocks/dataexchangemocks/callbacks.go b/mocks/dataexchangemocks/callbacks.go
index e39b409a0d..9bbf3c1252 100644
--- a/mocks/dataexchangemocks/callbacks.go
+++ b/mocks/dataexchangemocks/callbacks.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package dataexchangemocks
@@ -12,6 +12,11 @@ type Callbacks struct {
mock.Mock
}
+// DXConnect provides a mock function with given fields: plugin
+func (_m *Callbacks) DXConnect(plugin dataexchange.Plugin) {
+ _m.Called(plugin)
+}
+
// DXEvent provides a mock function with given fields: plugin, event
func (_m *Callbacks) DXEvent(plugin dataexchange.Plugin, event dataexchange.DXEvent) error {
ret := _m.Called(plugin, event)
diff --git a/mocks/dataexchangemocks/dx_event.go b/mocks/dataexchangemocks/dx_event.go
index 2ee5e469f6..a5d70b9a34 100644
--- a/mocks/dataexchangemocks/dx_event.go
+++ b/mocks/dataexchangemocks/dx_event.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package dataexchangemocks
diff --git a/mocks/dataexchangemocks/plugin.go b/mocks/dataexchangemocks/plugin.go
index ecd545651e..4ca67108a6 100644
--- a/mocks/dataexchangemocks/plugin.go
+++ b/mocks/dataexchangemocks/plugin.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package dataexchangemocks
@@ -15,6 +15,8 @@ import (
io "io"
+ metrics "github.com/hyperledger/firefly/internal/metrics"
+
mock "github.com/stretchr/testify/mock"
)
@@ -61,6 +63,24 @@ func (_m *Plugin) Capabilities() *dataexchange.Capabilities {
return r0
}
+// CheckNodeIdentityStatus provides a mock function with given fields: ctx, node
+func (_m *Plugin) CheckNodeIdentityStatus(ctx context.Context, node *core.Identity) error {
+ ret := _m.Called(ctx, node)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CheckNodeIdentityStatus")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, *core.Identity) error); ok {
+ r0 = rf(ctx, node)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
// DeleteBlob provides a mock function with given fields: ctx, payloadRef
func (_m *Plugin) DeleteBlob(ctx context.Context, payloadRef string) error {
ret := _m.Called(ctx, payloadRef)
@@ -157,17 +177,17 @@ func (_m *Plugin) GetPeerID(peer fftypes.JSONObject) string {
return r0
}
-// Init provides a mock function with given fields: ctx, cancelCtx, _a2
-func (_m *Plugin) Init(ctx context.Context, cancelCtx context.CancelFunc, _a2 config.Section) error {
- ret := _m.Called(ctx, cancelCtx, _a2)
+// Init provides a mock function with given fields: ctx, cancelCtx, _a2, _a3
+func (_m *Plugin) Init(ctx context.Context, cancelCtx context.CancelFunc, _a2 config.Section, _a3 metrics.Manager) error {
+ ret := _m.Called(ctx, cancelCtx, _a2, _a3)
if len(ret) == 0 {
panic("no return value specified for Init")
}
var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, context.CancelFunc, config.Section) error); ok {
- r0 = rf(ctx, cancelCtx, _a2)
+ if rf, ok := ret.Get(0).(func(context.Context, context.CancelFunc, config.Section, metrics.Manager) error); ok {
+ r0 = rf(ctx, cancelCtx, _a2, _a3)
} else {
r0 = ret.Error(0)
}
diff --git a/mocks/datamocks/manager.go b/mocks/datamocks/manager.go
index ef595ebd69..12725eeef1 100644
--- a/mocks/datamocks/manager.go
+++ b/mocks/datamocks/manager.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package datamocks
diff --git a/mocks/definitionsmocks/handler.go b/mocks/definitionsmocks/handler.go
index c4d2ba66f4..c7c5b38576 100644
--- a/mocks/definitionsmocks/handler.go
+++ b/mocks/definitionsmocks/handler.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package definitionsmocks
diff --git a/mocks/definitionsmocks/sender.go b/mocks/definitionsmocks/sender.go
index 23e487e476..d4720e15c7 100644
--- a/mocks/definitionsmocks/sender.go
+++ b/mocks/definitionsmocks/sender.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package definitionsmocks
diff --git a/mocks/eventmocks/event_manager.go b/mocks/eventmocks/event_manager.go
index a5fad4a769..6558286a48 100644
--- a/mocks/eventmocks/event_manager.go
+++ b/mocks/eventmocks/event_manager.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package eventmocks
diff --git a/mocks/eventsmocks/callbacks.go b/mocks/eventsmocks/callbacks.go
index f4ec135b9c..8b607a1ea8 100644
--- a/mocks/eventsmocks/callbacks.go
+++ b/mocks/eventsmocks/callbacks.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package eventsmocks
diff --git a/mocks/eventsmocks/plugin.go b/mocks/eventsmocks/plugin.go
index 2efc0a2425..48e0b2363e 100644
--- a/mocks/eventsmocks/plugin.go
+++ b/mocks/eventsmocks/plugin.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package eventsmocks
diff --git a/mocks/identitymanagermocks/manager.go b/mocks/identitymanagermocks/manager.go
index 51b648ea92..78a8316619 100644
--- a/mocks/identitymanagermocks/manager.go
+++ b/mocks/identitymanagermocks/manager.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package identitymanagermocks
@@ -183,6 +183,34 @@ func (_m *Manager) GetLocalNode(ctx context.Context) (*core.Identity, error) {
return r0, r1
}
+// GetLocalNodeDID provides a mock function with given fields: ctx
+func (_m *Manager) GetLocalNodeDID(ctx context.Context) (string, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetLocalNodeDID")
+ }
+
+ var r0 string
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (string, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) string); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
// GetRootOrg provides a mock function with given fields: ctx
func (_m *Manager) GetRootOrg(ctx context.Context) (*core.Identity, error) {
ret := _m.Called(ctx)
diff --git a/mocks/identitymocks/callbacks.go b/mocks/identitymocks/callbacks.go
index f3f9946f8f..49e2334c46 100644
--- a/mocks/identitymocks/callbacks.go
+++ b/mocks/identitymocks/callbacks.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package identitymocks
diff --git a/mocks/identitymocks/plugin.go b/mocks/identitymocks/plugin.go
index bdb0e52b8d..62c596a587 100644
--- a/mocks/identitymocks/plugin.go
+++ b/mocks/identitymocks/plugin.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package identitymocks
diff --git a/mocks/metricsmocks/manager.go b/mocks/metricsmocks/manager.go
index 33a5e7bd78..5c502e4d9c 100644
--- a/mocks/metricsmocks/manager.go
+++ b/mocks/metricsmocks/manager.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package metricsmocks
@@ -6,6 +6,8 @@ import (
fftypes "github.com/hyperledger/firefly-common/pkg/fftypes"
core "github.com/hyperledger/firefly/pkg/core"
+ metrics "github.com/hyperledger/firefly/internal/metrics"
+
mock "github.com/stretchr/testify/mock"
time "time"
@@ -41,9 +43,9 @@ func (_m *Manager) BlockchainTransaction(location string, methodName string) {
_m.Called(location, methodName)
}
-// CountBatchPin provides a mock function with given fields:
-func (_m *Manager) CountBatchPin() {
- _m.Called()
+// CountBatchPin provides a mock function with given fields: namespace
+func (_m *Manager) CountBatchPin(namespace string) {
+ _m.Called(namespace)
}
// DeleteTime provides a mock function with given fields: id
@@ -97,6 +99,16 @@ func (_m *Manager) MessageSubmitted(msg *core.Message) {
_m.Called(msg)
}
+// NodeIdentityDXCertExpiry provides a mock function with given fields: namespace, expiry
+func (_m *Manager) NodeIdentityDXCertExpiry(namespace string, expiry time.Time) {
+ _m.Called(namespace, expiry)
+}
+
+// NodeIdentityDXCertMismatch provides a mock function with given fields: namespace, mismatch
+func (_m *Manager) NodeIdentityDXCertMismatch(namespace string, mismatch metrics.NodeIdentityDXCertMismatchStatus) {
+ _m.Called(namespace, mismatch)
+}
+
// TransferConfirmed provides a mock function with given fields: transfer
func (_m *Manager) TransferConfirmed(transfer *core.TokenTransfer) {
_m.Called(transfer)
diff --git a/mocks/multipartymocks/manager.go b/mocks/multipartymocks/manager.go
index 65cf1ea118..c4d78d8d64 100644
--- a/mocks/multipartymocks/manager.go
+++ b/mocks/multipartymocks/manager.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package multipartymocks
diff --git a/mocks/namespacemocks/manager.go b/mocks/namespacemocks/manager.go
index fa6e9c5b39..1c29f3c8fd 100644
--- a/mocks/namespacemocks/manager.go
+++ b/mocks/namespacemocks/manager.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package namespacemocks
diff --git a/mocks/networkmapmocks/manager.go b/mocks/networkmapmocks/manager.go
index 2751287852..5e45660fd0 100644
--- a/mocks/networkmapmocks/manager.go
+++ b/mocks/networkmapmocks/manager.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package networkmapmocks
@@ -18,6 +18,24 @@ type Manager struct {
mock.Mock
}
+// CheckNodeIdentityStatus provides a mock function with given fields: ctx
+func (_m *Manager) CheckNodeIdentityStatus(ctx context.Context) error {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CheckNodeIdentityStatus")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context) error); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
// GetDIDDocForIndentityByDID provides a mock function with given fields: ctx, did
func (_m *Manager) GetDIDDocForIndentityByDID(ctx context.Context, did string) (*networkmap.DIDDocument, error) {
ret := _m.Called(ctx, did)
diff --git a/mocks/operationmocks/manager.go b/mocks/operationmocks/manager.go
index 98a2a22fed..9d3fcbe15c 100644
--- a/mocks/operationmocks/manager.go
+++ b/mocks/operationmocks/manager.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package operationmocks
@@ -268,8 +268,26 @@ func (_m *Manager) Start() error {
return r0
}
+// SubmitBulkOperationUpdates provides a mock function with given fields: ctx, updates
+func (_m *Manager) SubmitBulkOperationUpdates(ctx context.Context, updates []*core.OperationUpdate) error {
+ ret := _m.Called(ctx, updates)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SubmitBulkOperationUpdates")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, []*core.OperationUpdate) error); ok {
+ r0 = rf(ctx, updates)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
// SubmitOperationUpdate provides a mock function with given fields: update
-func (_m *Manager) SubmitOperationUpdate(update *core.OperationUpdate) {
+func (_m *Manager) SubmitOperationUpdate(update *core.OperationUpdateAsync) {
_m.Called(update)
}
diff --git a/mocks/orchestratormocks/orchestrator.go b/mocks/orchestratormocks/orchestrator.go
index 6f94f78900..2027fa90db 100644
--- a/mocks/orchestratormocks/orchestrator.go
+++ b/mocks/orchestratormocks/orchestrator.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package orchestratormocks
diff --git a/mocks/privatemessagingmocks/manager.go b/mocks/privatemessagingmocks/manager.go
index 8988ca5859..5ba8bedce8 100644
--- a/mocks/privatemessagingmocks/manager.go
+++ b/mocks/privatemessagingmocks/manager.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package privatemessagingmocks
diff --git a/mocks/shareddownloadmocks/callbacks.go b/mocks/shareddownloadmocks/callbacks.go
index 26bcd708f3..f5ec29ae16 100644
--- a/mocks/shareddownloadmocks/callbacks.go
+++ b/mocks/shareddownloadmocks/callbacks.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package shareddownloadmocks
diff --git a/mocks/shareddownloadmocks/manager.go b/mocks/shareddownloadmocks/manager.go
index 33226238f6..53c98a53ee 100644
--- a/mocks/shareddownloadmocks/manager.go
+++ b/mocks/shareddownloadmocks/manager.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package shareddownloadmocks
diff --git a/mocks/sharedstoragemocks/callbacks.go b/mocks/sharedstoragemocks/callbacks.go
index 6296a2b7c8..ee6a6afad3 100644
--- a/mocks/sharedstoragemocks/callbacks.go
+++ b/mocks/sharedstoragemocks/callbacks.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package sharedstoragemocks
diff --git a/mocks/sharedstoragemocks/plugin.go b/mocks/sharedstoragemocks/plugin.go
index a48e274235..4b7e61bde0 100644
--- a/mocks/sharedstoragemocks/plugin.go
+++ b/mocks/sharedstoragemocks/plugin.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package sharedstoragemocks
diff --git a/mocks/spieventsmocks/manager.go b/mocks/spieventsmocks/manager.go
index a61707c9aa..111ca05dff 100644
--- a/mocks/spieventsmocks/manager.go
+++ b/mocks/spieventsmocks/manager.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package spieventsmocks
diff --git a/mocks/syncasyncmocks/bridge.go b/mocks/syncasyncmocks/bridge.go
index bce0a36631..a5fe867ceb 100644
--- a/mocks/syncasyncmocks/bridge.go
+++ b/mocks/syncasyncmocks/bridge.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package syncasyncmocks
diff --git a/mocks/syncasyncmocks/sender.go b/mocks/syncasyncmocks/sender.go
index fd4bafa34f..41d2da4e0f 100644
--- a/mocks/syncasyncmocks/sender.go
+++ b/mocks/syncasyncmocks/sender.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package syncasyncmocks
diff --git a/mocks/systemeventmocks/event_interface.go b/mocks/systemeventmocks/event_interface.go
index dd0d4398ef..24650a858e 100644
--- a/mocks/systemeventmocks/event_interface.go
+++ b/mocks/systemeventmocks/event_interface.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package systemeventmocks
diff --git a/mocks/tokenmocks/callbacks.go b/mocks/tokenmocks/callbacks.go
index 36a362a344..da55fa787d 100644
--- a/mocks/tokenmocks/callbacks.go
+++ b/mocks/tokenmocks/callbacks.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package tokenmocks
diff --git a/mocks/tokenmocks/plugin.go b/mocks/tokenmocks/plugin.go
index b3292e799c..ea61d3d2a4 100644
--- a/mocks/tokenmocks/plugin.go
+++ b/mocks/tokenmocks/plugin.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package tokenmocks
diff --git a/mocks/txcommonmocks/helper.go b/mocks/txcommonmocks/helper.go
index 4fbbc91931..57ab913d65 100644
--- a/mocks/txcommonmocks/helper.go
+++ b/mocks/txcommonmocks/helper.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package txcommonmocks
diff --git a/mocks/txwritermocks/writer.go b/mocks/txwritermocks/writer.go
index 5358086e05..811a440907 100644
--- a/mocks/txwritermocks/writer.go
+++ b/mocks/txwritermocks/writer.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package txwritermocks
diff --git a/mocks/websocketsmocks/web_sockets_namespaced.go b/mocks/websocketsmocks/web_sockets_namespaced.go
index 2a036a3b1a..6c32559991 100644
--- a/mocks/websocketsmocks/web_sockets_namespaced.go
+++ b/mocks/websocketsmocks/web_sockets_namespaced.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package websocketsmocks
diff --git a/mocks/wsmocks/ws_client.go b/mocks/wsmocks/ws_client.go
index fccb7288b7..1a75210045 100644
--- a/mocks/wsmocks/ws_client.go
+++ b/mocks/wsmocks/ws_client.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.40.2. DO NOT EDIT.
+// Code generated by mockery v2.46.0. DO NOT EDIT.
package wsmocks
diff --git a/pkg/core/operation.go b/pkg/core/operation.go
index ff7a39607f..6cbd884ba3 100644
--- a/pkg/core/operation.go
+++ b/pkg/core/operation.go
@@ -1,4 +1,4 @@
-// Copyright ยฉ 2024 Kaleido, Inc.
+// Copyright ยฉ 2025 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -244,7 +244,9 @@ func ParseNamespacedOpID(ctx context.Context, nsIDStr string) (string, *fftypes.
}
type OperationCallbacks interface {
- OperationUpdate(update *OperationUpdate)
+ // This is an asynchronous update and you can use onComplete to signal the update has been committed to the DB through a function call
+ OperationUpdate(update *OperationUpdateAsync)
+ BulkOperationUpdates(ctx context.Context, updates []*OperationUpdate) error
}
// OperationUpdate notifies FireFly of an update to an operation.
@@ -262,7 +264,11 @@ type OperationUpdate struct {
VerifyManifest bool
DXManifest string
DXHash string
- OnComplete func()
+}
+
+type OperationUpdateAsync struct {
+ OperationUpdate
+ OnComplete func()
}
type OperationDetailError struct {
diff --git a/pkg/core/subscription.go b/pkg/core/subscription.go
index e9e789d1dc..bf9c4845c6 100644
--- a/pkg/core/subscription.go
+++ b/pkg/core/subscription.go
@@ -91,7 +91,7 @@ const (
// REMEMBER TO ADD OPTIONS HERE TO MarshalJSON()
type SubscriptionCoreOptions struct {
FirstEvent *SubOptsFirstEvent `ffstruct:"SubscriptionCoreOptions" json:"firstEvent,omitempty"`
- ReadAhead *uint16 `ffstruct:"SubscriptionCoreOptions" json:"readAhead,omitempty"`
+ ReadAhead *uint `ffstruct:"SubscriptionCoreOptions" json:"readAhead,omitempty"`
WithData *bool `ffstruct:"SubscriptionCoreOptions" json:"withData,omitempty"`
Batch *bool `ffstruct:"SubscriptionCoreOptions" json:"batch,omitempty"`
BatchTimeout *string `ffstruct:"SubscriptionCoreOptions" json:"batchTimeout,omitempty"`
diff --git a/pkg/core/subscription_test.go b/pkg/core/subscription_test.go
index 45d1ebf00c..2cae4ffddb 100644
--- a/pkg/core/subscription_test.go
+++ b/pkg/core/subscription_test.go
@@ -26,7 +26,7 @@ import (
func TestSubscriptionOptionsDatabaseSerialization(t *testing.T) {
firstEvent := SubOptsFirstEventNewest
- readAhead := uint16(50)
+ readAhead := uint(50)
yes := true
oneSec := "1s"
sub1 := &Subscription{
@@ -77,7 +77,7 @@ func TestSubscriptionOptionsDatabaseSerialization(t *testing.T) {
b2, err := sub1.Options.Value()
assert.NoError(t, err)
assert.Equal(t, SubOptsFirstEventNewest, *sub2.Options.FirstEvent)
- assert.Equal(t, uint16(50), *sub2.Options.ReadAhead)
+ assert.Equal(t, uint(50), *sub2.Options.ReadAhead)
assert.Equal(t, "myconfig", sub2.Options.TLSConfigName)
assert.Equal(t, string(b1.([]byte)), string(b2.([]byte)))
diff --git a/pkg/dataexchange/plugin.go b/pkg/dataexchange/plugin.go
index c6d5a407e1..a481f43c80 100644
--- a/pkg/dataexchange/plugin.go
+++ b/pkg/dataexchange/plugin.go
@@ -20,6 +20,8 @@ import (
"context"
"io"
+ "github.com/hyperledger/firefly/internal/metrics"
+
"github.com/hyperledger/firefly-common/pkg/config"
"github.com/hyperledger/firefly-common/pkg/fftypes"
"github.com/hyperledger/firefly/pkg/core"
@@ -60,7 +62,7 @@ type Plugin interface {
InitConfig(config config.Section)
// Init initializes the plugin, with configuration
- Init(ctx context.Context, cancelCtx context.CancelFunc, config config.Section) error
+ Init(ctx context.Context, cancelCtx context.CancelFunc, config config.Section, metrics metrics.Manager) error
// SetHandler registers a handler to receive callbacks
// Plugin will attempt (but is not guaranteed) to deliver events only for the given namespace and node
@@ -101,10 +103,14 @@ type Plugin interface {
// GetPeerID extracts the peer ID from the peer JSON
GetPeerID(peer fftypes.JSONObject) string
+
+ // CheckNodeIdentityStatus checks the status of the local node's network identity relative to the DX plugin's config
+ CheckNodeIdentityStatus(ctx context.Context, node *core.Identity) error
}
// Callbacks is the interface provided to the data exchange plugin, to allow it to pass events back to firefly.
type Callbacks interface {
+ DXConnect(plugin Plugin)
// Event has sub-types as defined below, and can be processed and ack'd asynchronously
DXEvent(plugin Plugin, event DXEvent) error
}
diff --git a/smart_contracts/ethereum/custompin_sample/package-lock.json b/smart_contracts/ethereum/custompin_sample/package-lock.json
index 5b60507fc1..66c8910f7a 100644
--- a/smart_contracts/ethereum/custompin_sample/package-lock.json
+++ b/smart_contracts/ethereum/custompin_sample/package-lock.json
@@ -16,6 +16,7 @@
}
},
"../solidity_firefly": {
+ "name": "@hyperledger/firefly-contracts",
"version": "0.0.1",
"devDependencies": {
"@nomicfoundation/hardhat-toolbox": "^5.0.0",
@@ -576,11 +577,11 @@
"@ethersproject/transactions": "^5.7.0",
"@ethersproject/web": "^5.7.0",
"bech32": "1.1.4",
- "ws": "7.4.6"
+ "ws": "7.5.10"
}
},
"node_modules/@ethersproject/providers/node_modules/ws": {
- "version": "7.4.6",
+ "version": "7.5.10",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
"integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==",
"dev": true,
@@ -686,7 +687,7 @@
"@ethersproject/logger": "^5.7.0",
"@ethersproject/properties": "^5.7.0",
"bn.js": "^5.2.1",
- "elliptic": "6.5.4",
+ "elliptic": "6.6.1",
"hash.js": "1.1.7"
}
},
@@ -955,7 +956,7 @@
"@types/bn.js": "^4.11.3",
"bn.js": "^4.11.0",
"create-hash": "^1.1.2",
- "elliptic": "^6.5.2",
+ "elliptic": "^6.6.1",
"ethereum-cryptography": "^0.1.3",
"ethjs-util": "0.1.6",
"rlp": "^2.2.3"
@@ -1039,174 +1040,89 @@
}
},
"node_modules/@nomicfoundation/edr": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.3.2.tgz",
- "integrity": "sha512-HGWtjibAK1mo4I2A7nJ/fXqe/J9G54OrSPJnnkY2K8TiXotYLShGd9GvHkae3PuFjTJKm6ZgBy7tveJj5yrCfw==",
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.7.0.tgz",
+ "integrity": "sha512-+Zyu7TE47TGNcPhOfWLPA/zISs32WDMXrhSWdWYyPHDVn/Uux5TVuOeScKb0BR/R8EJ+leR8COUF/EGxvDOVKg==",
"dev": true,
"peer": true,
+ "dependencies": {
+ "@nomicfoundation/edr-darwin-arm64": "0.7.0",
+ "@nomicfoundation/edr-darwin-x64": "0.7.0",
+ "@nomicfoundation/edr-linux-arm64-gnu": "0.7.0",
+ "@nomicfoundation/edr-linux-arm64-musl": "0.7.0",
+ "@nomicfoundation/edr-linux-x64-gnu": "0.7.0",
+ "@nomicfoundation/edr-linux-x64-musl": "0.7.0",
+ "@nomicfoundation/edr-win32-x64-msvc": "0.7.0"
+ },
"engines": {
"node": ">= 18"
- },
- "optionalDependencies": {
- "@nomicfoundation/edr-darwin-arm64": "0.3.2",
- "@nomicfoundation/edr-darwin-x64": "0.3.2",
- "@nomicfoundation/edr-linux-arm64-gnu": "0.3.2",
- "@nomicfoundation/edr-linux-arm64-musl": "0.3.2",
- "@nomicfoundation/edr-linux-x64-gnu": "0.3.2",
- "@nomicfoundation/edr-linux-x64-musl": "0.3.2",
- "@nomicfoundation/edr-win32-arm64-msvc": "0.3.2",
- "@nomicfoundation/edr-win32-ia32-msvc": "0.3.2",
- "@nomicfoundation/edr-win32-x64-msvc": "0.3.2"
}
},
"node_modules/@nomicfoundation/edr-darwin-arm64": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.3.2.tgz",
- "integrity": "sha512-l6wfSBUUbGJiCENT6272CDI8yoMuf0sZH56H5qz3HnAyVzenkOvmzyF6/lar54m986kdAQqWls4cLvDxiOuLxg==",
- "cpu": [
- "arm64"
- ],
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.7.0.tgz",
+ "integrity": "sha512-vAH20oh4GaSB/iQFTRcoO8jLc0CLd9XuLY9I7vtcqZWAiM4U1J4Y8cu67PWmtxbvUQOqXR7S6FtAr8/AlWm14g==",
"dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
"peer": true,
"engines": {
"node": ">= 18"
}
},
"node_modules/@nomicfoundation/edr-darwin-x64": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.3.2.tgz",
- "integrity": "sha512-OboExL7vEw+TRJQl3KkaEKU4K7PTdZPTInZ0fxMAtOpcWp7EKR+dQo68vc/iAOusB3xszHKxt7t+WpisItfdcg==",
- "cpu": [
- "x64"
- ],
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.7.0.tgz",
+ "integrity": "sha512-WHDdIrPvLlgXQr2eKypBM5xOZAwdxhDAEQIvEMQL8tEEm2qYW2bliUlssBPrs8E3bdivFbe1HizImslMAfU3+g==",
"dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
"peer": true,
"engines": {
"node": ">= 18"
}
},
"node_modules/@nomicfoundation/edr-linux-arm64-gnu": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.3.2.tgz",
- "integrity": "sha512-xtEK+1eg++3pHi6405NDXd80S3CGOFEGQIyVGCwjMGQFOLSzBGGCsrb/0GB4J19zd1o/8ftCd/HjZcbVAWWTLQ==",
- "cpu": [
- "arm64"
- ],
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.7.0.tgz",
+ "integrity": "sha512-WXpJB54ukz1no7gxCPXVEw9pgl/9UZ/WO3l1ctyv/T7vOygjqA4SUd6kppTs6MNXAuTiisPtvJ/fmvHiMBLrsw==",
"dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
"peer": true,
"engines": {
"node": ">= 18"
}
},
"node_modules/@nomicfoundation/edr-linux-arm64-musl": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.3.2.tgz",
- "integrity": "sha512-3cIsskJOXQ1yEVsImmCacY7O03tUTiWrmd54F05PnPFrDLkjbzodQ3b2gUWzfbzUZWl67ZTJd1CvVSzpe7XGzw==",
- "cpu": [
- "arm64"
- ],
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.7.0.tgz",
+ "integrity": "sha512-1iZYOcEgc+zJI7JQrlAFziuy9sBz1WgnIx3HIIu0J7lBRZ/AXeHHgATb+4InqxtEx9O3W8A0s7f11SyFqJL4Aw==",
"dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
"peer": true,
"engines": {
"node": ">= 18"
}
},
"node_modules/@nomicfoundation/edr-linux-x64-gnu": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.3.2.tgz",
- "integrity": "sha512-ouPdphHNsyO7wqwa4hwahC5WqBglK/fIvMmhR/SXNZ9qruIpsA8ZZKIURaHMOv/2h2BbNGcyTX9uEk6+5rK/MQ==",
- "cpu": [
- "x64"
- ],
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.7.0.tgz",
+ "integrity": "sha512-wSjC94WcR5MM8sg9w3OsAmT6+bbmChJw6uJKoXR3qscps/jdhjzJWzfgT0XGRq3XMUfimyafW2RWOyfX3ouhrQ==",
"dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
"peer": true,
"engines": {
"node": ">= 18"
}
},
"node_modules/@nomicfoundation/edr-linux-x64-musl": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.3.2.tgz",
- "integrity": "sha512-sRhwhiPbkpJMOUwXW1FZw9ks6xWyQhIhM0E8o3TXEXKSPKTE6whQLEk1R37iFITaI36vb6rSwLKTU1cb32gCoA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "peer": true,
- "engines": {
- "node": ">= 18"
- }
- },
- "node_modules/@nomicfoundation/edr-win32-arm64-msvc": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-arm64-msvc/-/edr-win32-arm64-msvc-0.3.2.tgz",
- "integrity": "sha512-IEwVealKfumu1HSSnama26yPuQC/uthRPK5IWtFsQUOGwOXaS1r9Bu7cGYH2jBHl3IT/JbxD4xzPq/2pM9uK0A==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "peer": true,
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@nomicfoundation/edr-win32-ia32-msvc": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-ia32-msvc/-/edr-win32-ia32-msvc-0.3.2.tgz",
- "integrity": "sha512-jYMnf6SFgguqROswwdsjJ1wvneD/5c16pVu9OD4DxNqhKNP5bHEw6L2N4DcJ89tpXMpJ6AlOpc0QuwzddiZ3tA==",
- "cpu": [
- "ia32"
- ],
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.7.0.tgz",
+ "integrity": "sha512-Us22+AZ7wkG1mZwxqE4S4ZcuwkEA5VrUiBOJSvKHGOgy6vFvB/Euh5Lkp4GovwjrtiXuvyGO2UmtkzymZKDxZw==",
"dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
"peer": true,
"engines": {
"node": ">= 18"
}
},
"node_modules/@nomicfoundation/edr-win32-x64-msvc": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.3.2.tgz",
- "integrity": "sha512-Byn4QuWczRy/DUUQM3WjglgX/jGVUURVFaUsmIhnGg//MPlCLawubBGRqsrMuvaYedlIIJ4I2rgKvZlxdgHrqg==",
- "cpu": [
- "x64"
- ],
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.7.0.tgz",
+ "integrity": "sha512-HAry0heTsWkzReVtjHwoIq3BgFCvXpVhJ5qPmTnegZGsr/KxqvMmHyDMifzKao4bycU8yrpTSyOiAJt27RWjzQ==",
"dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
"peer": true,
"engines": {
"node": ">= 18"
@@ -1282,9 +1198,9 @@
}
},
"node_modules/@nomicfoundation/hardhat-chai-matchers": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-2.0.6.tgz",
- "integrity": "sha512-Te1Uyo9oJcTCF0Jy9dztaLpshmlpjLf2yPtWXlXuLjMt3RRSmJLm/+rKVTW6gfadAEs12U/it6D0ZRnnRGiICQ==",
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-2.0.8.tgz",
+ "integrity": "sha512-Z5PiCXH4xhNLASROlSUOADfhfpfhYO6D7Hn9xp8PddmHey0jq704cr6kfU8TRrQ4PUZbpfsZadPj+pCfZdjPIg==",
"dev": true,
"peer": true,
"dependencies": {
@@ -1301,9 +1217,9 @@
}
},
"node_modules/@nomicfoundation/hardhat-ethers": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-3.0.5.tgz",
- "integrity": "sha512-RNFe8OtbZK6Ila9kIlHp0+S80/0Bu/3p41HUpaRIoHLm6X3WekTd83vob3rE54Duufu1edCiBDxspBzi2rxHHw==",
+ "version": "3.0.8",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-3.0.8.tgz",
+ "integrity": "sha512-zhOZ4hdRORls31DTOqg+GmEZM0ujly8GGIuRY7t7szEk2zW/arY1qDug/py8AEktT00v5K+b6RvbVog+va51IA==",
"dev": true,
"peer": true,
"dependencies": {
@@ -1316,17 +1232,18 @@
}
},
"node_modules/@nomicfoundation/hardhat-ignition": {
- "version": "0.15.0",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition/-/hardhat-ignition-0.15.0.tgz",
- "integrity": "sha512-GbAe90O22uM67U/JnffXX+mBMn0HqCKSH+D98Tb5uWqR1N/M00cB3yY8OdqzVai7I6SuIKTc91mPdvtWt8R3MA==",
+ "version": "0.15.9",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition/-/hardhat-ignition-0.15.9.tgz",
+ "integrity": "sha512-lSWqhaDOBt6gsqMadkRLvH6HdoFV1v8/bx7z+12cghaOloVwwn48CPoTH2iXXnkqilPGw8rdH5eVTE6UM+2v6Q==",
"dev": true,
"peer": true,
"dependencies": {
- "@nomicfoundation/ignition-core": "^0.15.0",
- "@nomicfoundation/ignition-ui": "^0.15.0",
+ "@nomicfoundation/ignition-core": "^0.15.9",
+ "@nomicfoundation/ignition-ui": "^0.15.9",
"chalk": "^4.0.0",
"debug": "^4.3.2",
"fs-extra": "^10.0.0",
+ "json5": "^2.2.3",
"prompts": "^2.4.2"
},
"peerDependencies": {
@@ -1335,23 +1252,23 @@
}
},
"node_modules/@nomicfoundation/hardhat-ignition-ethers": {
- "version": "0.15.0",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition-ethers/-/hardhat-ignition-ethers-0.15.0.tgz",
- "integrity": "sha512-KmMNUc/jptfwdPA9ukQf+Ajon+m2vLBjDL2ze7d/vQdrS+fDxmoVwmbbEk4GOjianZcwgQOWD9dEWaj04QiowA==",
+ "version": "0.15.9",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition-ethers/-/hardhat-ignition-ethers-0.15.9.tgz",
+ "integrity": "sha512-9PwwgLv3z2ec3B26mK0IjiFezHFFBcBcs1qKaRu8SanARE4b7RvrfiLIy8ZXE7HaxgPt32kSsQzehhzAwAIj1Q==",
"dev": true,
"peer": true,
"peerDependencies": {
"@nomicfoundation/hardhat-ethers": "^3.0.4",
- "@nomicfoundation/hardhat-ignition": "^0.15.0",
- "@nomicfoundation/ignition-core": "^0.15.0",
+ "@nomicfoundation/hardhat-ignition": "^0.15.9",
+ "@nomicfoundation/ignition-core": "^0.15.9",
"ethers": "^6.7.0",
"hardhat": "^2.18.0"
}
},
"node_modules/@nomicfoundation/hardhat-network-helpers": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.10.tgz",
- "integrity": "sha512-R35/BMBlx7tWN5V6d/8/19QCwEmIdbnA4ZrsuXgvs8i2qFx5i7h6mH5pBS4Pwi4WigLH+upl6faYusrNPuzMrQ==",
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.12.tgz",
+ "integrity": "sha512-xTNQNI/9xkHvjmCJnJOTyqDSl8uq1rKb2WOVmixQxFtRd7Oa3ecO8zM0cyC2YmOK+jHB9WPZ+F/ijkHg1CoORA==",
"dev": true,
"peer": true,
"dependencies": {
@@ -1388,18 +1305,18 @@
}
},
"node_modules/@nomicfoundation/hardhat-verify": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.0.5.tgz",
- "integrity": "sha512-Tg4zu8RkWpyADSFIgF4FlJIUEI4VkxcvELsmbJn2OokbvH2SnUrqKmw0BBfDrtvP0hhmx8wsnrRKP5DV/oTyTA==",
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.0.12.tgz",
+ "integrity": "sha512-Lg3Nu7DCXASQRVI/YysjuAX2z8jwOCbS0w5tz2HalWGSTZThqA0v9N0v0psHbKNqzPJa8bNOeapIVSziyJTnAg==",
"dev": true,
"peer": true,
"dependencies": {
"@ethersproject/abi": "^5.1.2",
"@ethersproject/address": "^5.0.2",
"cbor": "^8.1.0",
- "chalk": "^2.4.2",
"debug": "^4.1.1",
"lodash.clonedeep": "^4.5.0",
+ "picocolors": "^1.1.0",
"semver": "^6.3.0",
"table": "^6.8.0",
"undici": "^5.14.0"
@@ -1408,92 +1325,15 @@
"hardhat": "^2.0.4"
}
},
- "node_modules/@nomicfoundation/hardhat-verify/node_modules/ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "color-convert": "^1.9.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@nomicfoundation/hardhat-verify/node_modules/chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@nomicfoundation/hardhat-verify/node_modules/color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "color-name": "1.1.3"
- }
- },
- "node_modules/@nomicfoundation/hardhat-verify/node_modules/color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
- "dev": true,
- "peer": true
- },
- "node_modules/@nomicfoundation/hardhat-verify/node_modules/escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "dev": true,
- "peer": true,
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/@nomicfoundation/hardhat-verify/node_modules/has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "dev": true,
- "peer": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@nomicfoundation/hardhat-verify/node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/@nomicfoundation/ignition-core": {
- "version": "0.15.0",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-core/-/ignition-core-0.15.0.tgz",
- "integrity": "sha512-d/h8jgJHY4xIroHqdaGeTkTqjQeuzmU759AOn1Fg88cuxVhS7JM22ZI0bQWyLNSMsVstHBIo+lSMIsvm9jBF2w==",
+ "version": "0.15.9",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-core/-/ignition-core-0.15.9.tgz",
+ "integrity": "sha512-X8W+7UP/UQPorpHUnGvA1OdsEr/edGi8tDpNwEqzaLm83FMZVbRWdOsr3vNICHN2XMzNY/xIm18Cx7xGKL2PQw==",
"dev": true,
"peer": true,
"dependencies": {
"@ethersproject/address": "5.6.1",
+ "@nomicfoundation/solidity-analyzer": "^0.1.1",
"cbor": "^9.0.0",
"debug": "^4.3.2",
"ethers": "^6.7.0",
@@ -1541,9 +1381,9 @@
}
},
"node_modules/@nomicfoundation/ignition-ui": {
- "version": "0.15.0",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-ui/-/ignition-ui-0.15.0.tgz",
- "integrity": "sha512-RBvvQ0e8RcEc/LoSzNTPVKZZ5vEwlmxt7PXG278+6DqCrOqxqmh6W9PtK/4mwwvnTeBqds+8j81jDf6vJbOVBQ==",
+ "version": "0.15.9",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-ui/-/ignition-ui-0.15.9.tgz",
+ "integrity": "sha512-8lzbT7gpJ5PoowPQDQilkwdyqBviUKDMoHp/5rhgnwG1bDslnCS+Lxuo6s9R2akWu9LtEL14dNyqQb6WsURTag==",
"dev": true,
"peer": true
},
@@ -1884,7 +1724,7 @@
"@sentry/tracing": "5.30.0",
"@sentry/types": "5.30.0",
"@sentry/utils": "5.30.0",
- "cookie": "^0.4.1",
+ "cookie": "^1.0.2",
"https-proxy-agent": "^5.0.0",
"lru_map": "^0.3.3",
"tslib": "^1.9.3"
@@ -2121,13 +1961,13 @@
"peer": true
},
"node_modules/@types/node": {
- "version": "20.11.28",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.28.tgz",
- "integrity": "sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==",
+ "version": "22.7.5",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz",
+ "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==",
"dev": true,
"peer": true,
"dependencies": {
- "undici-types": "~5.26.4"
+ "undici-types": "~6.19.2"
}
},
"node_modules/@types/pbkdf2": {
@@ -2445,9 +2285,9 @@
}
},
"node_modules/axios": {
- "version": "1.6.8",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz",
- "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==",
+ "version": "1.7.9",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
+ "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
"dev": true,
"peer": true,
"dependencies": {
@@ -2555,13 +2395,13 @@
}
},
"node_modules/braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"peer": true,
"dependencies": {
- "fill-range": "^7.0.1"
+ "fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
@@ -2768,28 +2608,33 @@
}
},
"node_modules/chokidar": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
- "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+ "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
"dev": true,
"peer": true,
"dependencies": {
- "anymatch": "~3.1.2",
- "braces": "~3.0.2",
- "glob-parent": "~5.1.2",
- "is-binary-path": "~2.1.0",
- "is-glob": "~4.0.1",
- "normalize-path": "~3.0.0",
- "readdirp": "~3.6.0"
+ "readdirp": "^4.0.1"
},
"engines": {
- "node": ">= 8.10.0"
+ "node": ">= 14.16.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/chokidar/node_modules/readdirp": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
+ "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">= 14.18.0"
},
- "optionalDependencies": {
- "fsevents": "~2.3.2"
+ "funding": {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
}
},
"node_modules/ci-info": {
@@ -3090,11 +2935,14 @@
}
},
"node_modules/commander": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz",
- "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==",
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
+ "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
"dev": true,
- "peer": true
+ "peer": true,
+ "engines": {
+ "node": ">= 12"
+ }
},
"node_modules/concat-map": {
"version": "0.0.1",
@@ -3153,13 +3001,13 @@
}
},
"node_modules/cookie": {
- "version": "0.4.2",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
- "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
+ "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
"dev": true,
"peer": true,
"engines": {
- "node": ">= 0.6"
+ "node": ">=18"
}
},
"node_modules/core-util-is": {
@@ -3223,13 +3071,13 @@
"peer": true
},
"node_modules/debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+ "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"dev": true,
"peer": true,
"dependencies": {
- "ms": "2.1.2"
+ "ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
@@ -3322,9 +3170,9 @@
}
},
"node_modules/diff": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
- "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz",
+ "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==",
"dev": true,
"peer": true,
"engines": {
@@ -3358,9 +3206,9 @@
}
},
"node_modules/elliptic": {
- "version": "6.5.4",
- "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
- "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
+ "version": "6.6.1",
+ "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz",
+ "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==",
"dev": true,
"peer": true,
"dependencies": {
@@ -3726,7 +3574,7 @@
"@types/bn.js": "^4.11.3",
"bn.js": "^4.11.0",
"create-hash": "^1.1.2",
- "elliptic": "^6.5.2",
+ "elliptic": "^6.6.1",
"ethereum-cryptography": "^0.1.3",
"ethjs-util": "0.1.6",
"rlp": "^2.2.3"
@@ -3750,9 +3598,9 @@
}
},
"node_modules/ethers": {
- "version": "6.11.1",
- "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.11.1.tgz",
- "integrity": "sha512-mxTAE6wqJQAbp5QAe/+o+rXOID7Nw91OZXvgpjDa1r4fAbq2Nu314oEZSbjoRLacuCzs7kUC3clEvkCQowffGg==",
+ "version": "6.13.5",
+ "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.13.5.tgz",
+ "integrity": "sha512-+knKNieu5EKRThQJWwqaJ10a6HE9sSehGeqWN65//wE7j47ZpFhKAnHB/JJFibwwg61I/koxaPsXbXpD/skNOQ==",
"dev": true,
"funding": [
{
@@ -3769,21 +3617,36 @@
"@adraffy/ens-normalize": "1.10.1",
"@noble/curves": "1.2.0",
"@noble/hashes": "1.3.2",
- "@types/node": "18.15.13",
+ "@types/node": "22.7.5",
"aes-js": "4.0.0-beta.5",
- "tslib": "2.4.0",
- "ws": "8.5.0"
+ "tslib": "2.7.0",
+ "ws": "8.17.1"
},
"engines": {
"node": ">=14.0.0"
}
},
- "node_modules/ethers/node_modules/@types/node": {
- "version": "18.15.13",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz",
- "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==",
+ "node_modules/ethers/node_modules/ws": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
+ "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"dev": true,
- "peer": true
+ "peer": true,
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
},
"node_modules/ethjs-unit": {
"version": "0.1.6",
@@ -3875,9 +3738,9 @@
}
},
"node_modules/fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"peer": true,
"dependencies": {
@@ -3901,16 +3764,20 @@
}
},
"node_modules/find-up": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
- "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
"dev": true,
"peer": true,
"dependencies": {
- "locate-path": "^2.0.0"
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
},
"engines": {
- "node": ">=4"
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/flat": {
@@ -4297,15 +4164,15 @@
}
},
"node_modules/hardhat": {
- "version": "2.22.1",
- "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.1.tgz",
- "integrity": "sha512-cTWYIJc5jQ132XUI8oRI/TO9L6oavPoJRCTRU9sIjkVxvkxz0Axz0K83Z3BEdJTqBQ2W84ZRoTekti84kBwCjg==",
+ "version": "2.22.18",
+ "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.18.tgz",
+ "integrity": "sha512-2+kUz39gvMo56s75cfLBhiFedkQf+gXdrwCcz4R/5wW0oBdwiyfj2q9BIkMoaA0WIGYYMU2I1Cc4ucTunhfjzw==",
"dev": true,
"peer": true,
"dependencies": {
"@ethersproject/abi": "^5.1.2",
"@metamask/eth-sig-util": "^4.0.0",
- "@nomicfoundation/edr": "^0.3.1",
+ "@nomicfoundation/edr": "^0.7.0",
"@nomicfoundation/ethereumjs-common": "4.0.4",
"@nomicfoundation/ethereumjs-tx": "5.0.4",
"@nomicfoundation/ethereumjs-util": "9.0.4",
@@ -4317,35 +4184,36 @@
"aggregate-error": "^3.0.0",
"ansi-escapes": "^4.3.0",
"boxen": "^5.1.2",
- "chalk": "^2.4.2",
- "chokidar": "^3.4.0",
+ "chokidar": "^4.0.0",
"ci-info": "^2.0.0",
"debug": "^4.1.1",
"enquirer": "^2.3.0",
"env-paths": "^2.2.0",
"ethereum-cryptography": "^1.0.3",
"ethereumjs-abi": "^0.6.8",
- "find-up": "^2.1.0",
+ "find-up": "^5.0.0",
"fp-ts": "1.19.3",
"fs-extra": "^7.0.1",
- "glob": "7.2.0",
"immutable": "^4.0.0-rc.12",
"io-ts": "1.10.4",
+ "json-stream-stringify": "^3.1.4",
"keccak": "^3.0.2",
"lodash": "^4.17.11",
"mnemonist": "^0.38.0",
"mocha": "^10.0.0",
"p-map": "^4.0.0",
+ "picocolors": "^1.1.0",
"raw-body": "^2.4.1",
"resolve": "1.17.0",
"semver": "^6.3.0",
- "solc": "0.7.3",
+ "solc": "0.8.26",
"source-map-support": "^0.5.13",
"stacktrace-parser": "^0.1.10",
+ "tinyglobby": "^0.2.6",
"tsort": "0.0.1",
"undici": "^5.14.0",
"uuid": "^8.3.2",
- "ws": "^7.4.6"
+ "ws": "^7.5.10"
},
"bin": {
"hardhat": "internal/cli/bootstrap.js"
@@ -4426,99 +4294,34 @@
"@scure/base": "~1.1.0"
}
},
- "node_modules/hardhat/node_modules/ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "node_modules/hardhat/node_modules/ethereum-cryptography": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz",
+ "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==",
"dev": true,
"peer": true,
"dependencies": {
- "color-convert": "^1.9.0"
- },
- "engines": {
- "node": ">=4"
+ "@noble/hashes": "1.2.0",
+ "@noble/secp256k1": "1.7.1",
+ "@scure/bip32": "1.1.5",
+ "@scure/bip39": "1.1.1"
}
},
- "node_modules/hardhat/node_modules/chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "node_modules/hardhat/node_modules/fs-extra": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
+ "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
"dev": true,
"peer": true,
"dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/hardhat/node_modules/color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "color-name": "1.1.3"
- }
- },
- "node_modules/hardhat/node_modules/color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
- "dev": true,
- "peer": true
- },
- "node_modules/hardhat/node_modules/escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "dev": true,
- "peer": true,
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/hardhat/node_modules/ethereum-cryptography": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz",
- "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "@noble/hashes": "1.2.0",
- "@noble/secp256k1": "1.7.1",
- "@scure/bip32": "1.1.5",
- "@scure/bip39": "1.1.1"
- }
- },
- "node_modules/hardhat/node_modules/fs-extra": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
- "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "graceful-fs": "^4.1.2",
- "jsonfile": "^4.0.0",
- "universalify": "^0.1.0"
+ "graceful-fs": "^4.1.2",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
},
"engines": {
"node": ">=6 <7 || >=8"
}
},
- "node_modules/hardhat/node_modules/has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "dev": true,
- "peer": true,
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/hardhat/node_modules/jsonfile": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
@@ -4529,19 +4332,6 @@
"graceful-fs": "^4.1.6"
}
},
- "node_modules/hardhat/node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/hardhat/node_modules/universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
@@ -4553,9 +4343,9 @@
}
},
"node_modules/hardhat/node_modules/ws": {
- "version": "7.5.9",
- "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
- "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
+ "version": "7.5.10",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
+ "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"dev": true,
"peer": true,
"engines": {
@@ -4982,6 +4772,16 @@
"dev": true,
"peer": true
},
+ "node_modules/json-stream-stringify": {
+ "version": "3.1.6",
+ "resolved": "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-3.1.6.tgz",
+ "integrity": "sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=7.10.1"
+ }
+ },
"node_modules/json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
@@ -4989,6 +4789,19 @@
"dev": true,
"peer": true
},
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "peer": true,
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/jsonfile": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
@@ -5038,16 +4851,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/klaw": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz",
- "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==",
- "dev": true,
- "peer": true,
- "optionalDependencies": {
- "graceful-fs": "^4.1.9"
- }
- },
"node_modules/kleur": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
@@ -5073,17 +4876,19 @@
}
},
"node_modules/locate-path": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
- "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
"dev": true,
"peer": true,
"dependencies": {
- "p-locate": "^2.0.0",
- "path-exists": "^3.0.0"
+ "p-locate": "^5.0.0"
},
"engines": {
- "node": ">=4"
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/lodash": {
@@ -5222,13 +5027,13 @@
"peer": true
},
"node_modules/micromatch": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
- "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true,
"peer": true,
"dependencies": {
- "braces": "^3.0.2",
+ "braces": "^3.0.3",
"picomatch": "^2.3.1"
},
"engines": {
@@ -5319,32 +5124,32 @@
}
},
"node_modules/mocha": {
- "version": "10.3.0",
- "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.3.0.tgz",
- "integrity": "sha512-uF2XJs+7xSLsrmIvn37i/wnc91nw7XjOQB8ccyx5aEgdnohr7n+rEiZP23WkCYHjilR6+EboEnbq/ZQDz4LSbg==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "ansi-colors": "4.1.1",
- "browser-stdout": "1.3.1",
- "chokidar": "3.5.3",
- "debug": "4.3.4",
- "diff": "5.0.0",
- "escape-string-regexp": "4.0.0",
- "find-up": "5.0.0",
- "glob": "8.1.0",
- "he": "1.2.0",
- "js-yaml": "4.1.0",
- "log-symbols": "4.1.0",
- "minimatch": "5.0.1",
- "ms": "2.1.3",
- "serialize-javascript": "6.0.0",
- "strip-json-comments": "3.1.1",
- "supports-color": "8.1.1",
- "workerpool": "6.2.1",
- "yargs": "16.2.0",
- "yargs-parser": "20.2.4",
- "yargs-unparser": "2.0.0"
+ "version": "10.8.2",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz",
+ "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "ansi-colors": "^4.1.3",
+ "browser-stdout": "^1.3.1",
+ "chokidar": "^3.5.3",
+ "debug": "^4.3.5",
+ "diff": "^5.2.0",
+ "escape-string-regexp": "^4.0.0",
+ "find-up": "^5.0.0",
+ "glob": "^8.1.0",
+ "he": "^1.2.0",
+ "js-yaml": "^4.1.0",
+ "log-symbols": "^4.1.0",
+ "minimatch": "^5.1.6",
+ "ms": "^2.1.3",
+ "serialize-javascript": "^6.0.2",
+ "strip-json-comments": "^3.1.1",
+ "supports-color": "^8.1.1",
+ "workerpool": "^6.5.1",
+ "yargs": "^16.2.0",
+ "yargs-parser": "^20.2.9",
+ "yargs-unparser": "^2.0.0"
},
"bin": {
"_mocha": "bin/_mocha",
@@ -5354,16 +5159,6 @@
"node": ">= 14.0.0"
}
},
- "node_modules/mocha/node_modules/ansi-colors": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
- "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
- "dev": true,
- "peer": true,
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/mocha/node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
@@ -5402,23 +5197,6 @@
"fsevents": "~2.3.2"
}
},
- "node_modules/mocha/node_modules/find-up": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
- "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "locate-path": "^6.0.0",
- "path-exists": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/mocha/node_modules/glob": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
@@ -5439,26 +5217,10 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/mocha/node_modules/locate-path": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
- "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "p-locate": "^5.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/mocha/node_modules/minimatch": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
- "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
"dev": true,
"peer": true,
"dependencies": {
@@ -5468,55 +5230,6 @@
"node": ">=10"
}
},
- "node_modules/mocha/node_modules/ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
- "dev": true,
- "peer": true
- },
- "node_modules/mocha/node_modules/p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "yocto-queue": "^0.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/mocha/node_modules/p-locate": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
- "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "p-limit": "^3.0.2"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/mocha/node_modules/path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true,
- "peer": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/mocha/node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
@@ -5534,9 +5247,9 @@
}
},
"node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true,
"peer": true
},
@@ -5724,29 +5437,35 @@
}
},
"node_modules/p-limit": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
- "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
"dev": true,
"peer": true,
"dependencies": {
- "p-try": "^1.0.0"
+ "yocto-queue": "^0.1.0"
},
"engines": {
- "node": ">=4"
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-locate": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
- "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
"dev": true,
"peer": true,
"dependencies": {
- "p-limit": "^1.1.0"
+ "p-limit": "^3.0.2"
},
"engines": {
- "node": ">=4"
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-map": {
@@ -5765,16 +5484,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/p-try": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
- "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==",
- "dev": true,
- "peer": true,
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/parse-cache-control": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz",
@@ -5783,13 +5492,13 @@
"peer": true
},
"node_modules/path-exists": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
- "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true,
"peer": true,
"engines": {
- "node": ">=4"
+ "node": ">=8"
}
},
"node_modules/path-is-absolute": {
@@ -5846,6 +5555,13 @@
"node": ">=0.12"
}
},
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "peer": true
+ },
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
@@ -6150,19 +5866,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/rimraf": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
- "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "glob": "^7.1.3"
- },
- "bin": {
- "rimraf": "bin.js"
- }
- },
"node_modules/ripemd160": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
@@ -6358,21 +6061,28 @@
"peer": true
},
"node_modules/secp256k1": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz",
- "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.4.tgz",
+ "integrity": "sha512-6JfvwvjUOn8F/jUoBY2Q1v5WY5XS+rj8qSe0v8Y4ezH4InLgTEeOOPQsRll9OV429Pvo6BCHGavIyJfr3TAhsw==",
"dev": true,
"hasInstallScript": true,
"peer": true,
"dependencies": {
- "elliptic": "^6.5.4",
- "node-addon-api": "^2.0.0",
+ "elliptic": "^6.6.1",
+ "node-addon-api": "^5.0.0",
"node-gyp-build": "^4.2.0"
},
"engines": {
- "node": ">=10.0.0"
+ "node": ">=18.0.0"
}
},
+ "node_modules/secp256k1/node_modules/node-addon-api": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz",
+ "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==",
+ "dev": true,
+ "peer": true
+ },
"node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
@@ -6384,9 +6094,9 @@
}
},
"node_modules/serialize-javascript": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
- "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
+ "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
"dev": true,
"peer": true,
"dependencies": {
@@ -6526,51 +6236,25 @@
}
},
"node_modules/solc": {
- "version": "0.7.3",
- "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz",
- "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==",
+ "version": "0.8.26",
+ "resolved": "https://registry.npmjs.org/solc/-/solc-0.8.26.tgz",
+ "integrity": "sha512-yiPQNVf5rBFHwN6SIf3TUUvVAFKcQqmSUFeq+fb6pNRCo0ZCgpYOZDi3BVoezCPIAcKrVYd/qXlBLUP9wVrZ9g==",
"dev": true,
"peer": true,
"dependencies": {
"command-exists": "^1.2.8",
- "commander": "3.0.2",
+ "commander": "^8.1.0",
"follow-redirects": "^1.12.1",
- "fs-extra": "^0.30.0",
"js-sha3": "0.8.0",
"memorystream": "^0.3.1",
- "require-from-string": "^2.0.0",
"semver": "^5.5.0",
"tmp": "0.0.33"
},
"bin": {
- "solcjs": "solcjs"
+ "solcjs": "solc.js"
},
"engines": {
- "node": ">=8.0.0"
- }
- },
- "node_modules/solc/node_modules/fs-extra": {
- "version": "0.30.0",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz",
- "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "graceful-fs": "^4.1.2",
- "jsonfile": "^2.1.0",
- "klaw": "^1.0.0",
- "path-is-absolute": "^1.0.0",
- "rimraf": "^2.2.8"
- }
- },
- "node_modules/solc/node_modules/jsonfile": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
- "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==",
- "dev": true,
- "peer": true,
- "optionalDependencies": {
- "graceful-fs": "^4.1.6"
+ "node": ">=10.0.0"
}
},
"node_modules/solc/node_modules/semver": {
@@ -6584,14 +6268,14 @@
}
},
"node_modules/solidity-coverage": {
- "version": "0.8.11",
- "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.11.tgz",
- "integrity": "sha512-yy0Yk+olovBbXn0Me8BWULmmv7A69ZKkP5aTOJGOO8u61Tu2zS989erfjtFlUjDnfWtxRAVkd8BsQD704yLWHw==",
+ "version": "0.8.14",
+ "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.14.tgz",
+ "integrity": "sha512-ItAAObe5GaEOp20kXC2BZRnph+9P7Rtoqg2mQc2SXGEHgSDF2wWd1Wxz3ntzQWXkbCtIIGdJT918HG00cObwbA==",
"dev": true,
"peer": true,
"dependencies": {
"@ethersproject/abi": "^5.0.9",
- "@solidity-parser/parser": "^0.18.0",
+ "@solidity-parser/parser": "^0.19.0",
"chalk": "^2.4.2",
"death": "^1.1.0",
"difflib": "^0.2.4",
@@ -6600,7 +6284,7 @@
"global-modules": "^2.0.0",
"globby": "^10.0.1",
"jsonschema": "^1.2.4",
- "lodash": "^4.17.15",
+ "lodash": "^4.17.21",
"mocha": "^10.2.0",
"node-emoji": "^1.10.0",
"pify": "^4.0.1",
@@ -6618,9 +6302,9 @@
}
},
"node_modules/solidity-coverage/node_modules/@solidity-parser/parser": {
- "version": "0.18.0",
- "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.18.0.tgz",
- "integrity": "sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA==",
+ "version": "0.19.0",
+ "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.19.0.tgz",
+ "integrity": "sha512-RV16k/qIxW/wWc+mLzV3ARyKUaMUTBy9tOLMzFhtNSKYeTAanQ3a5MudJKf/8arIFnA2L27SNjarQKmFg0w/jA==",
"dev": true,
"peer": true
},
@@ -7056,6 +6740,51 @@
"readable-stream": "3"
}
},
+ "node_modules/tinyglobby": {
+ "version": "0.2.11",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.11.tgz",
+ "integrity": "sha512-32TmKeeKUahv0Go8WmQgiEp9Y21NuxjwjqiRC1nrUB51YacfSwuB44xgXD+HdIppmMRgjQNPdrHyA6vIybYZ+g==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "fdir": "^6.4.3",
+ "picomatch": "^4.0.2"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/tinyglobby/node_modules/fdir": {
+ "version": "6.4.3",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz",
+ "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==",
+ "dev": true,
+ "peer": true,
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tinyglobby/node_modules/picomatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
+ "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
"node_modules/tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@@ -7173,9 +6902,9 @@
}
},
"node_modules/tslib": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
- "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
+ "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",
"dev": true,
"peer": true
},
@@ -7375,9 +7104,9 @@
}
},
"node_modules/undici": {
- "version": "5.28.3",
- "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz",
- "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==",
+ "version": "5.28.5",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.5.tgz",
+ "integrity": "sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==",
"dev": true,
"peer": true,
"dependencies": {
@@ -7388,9 +7117,9 @@
}
},
"node_modules/undici-types": {
- "version": "5.26.5",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
- "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+ "version": "6.19.8",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
+ "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"dev": true,
"peer": true
},
@@ -7582,9 +7311,9 @@
}
},
"node_modules/workerpool": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
- "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz",
+ "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==",
"dev": true,
"peer": true
},
@@ -7613,28 +7342,6 @@
"dev": true,
"peer": true
},
- "node_modules/ws": {
- "version": "8.5.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz",
- "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==",
- "dev": true,
- "peer": true,
- "engines": {
- "node": ">=10.0.0"
- },
- "peerDependencies": {
- "bufferutil": "^4.0.1",
- "utf-8-validate": "^5.0.2"
- },
- "peerDependenciesMeta": {
- "bufferutil": {
- "optional": true
- },
- "utf-8-validate": {
- "optional": true
- }
- }
- },
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
@@ -7672,9 +7379,9 @@
}
},
"node_modules/yargs-parser": {
- "version": "20.2.4",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
- "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
+ "version": "20.2.9",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+ "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
"dev": true,
"peer": true,
"engines": {
diff --git a/smart_contracts/ethereum/solidity_firefly/package-lock.json b/smart_contracts/ethereum/solidity_firefly/package-lock.json
index a3d36ef320..c911f7a69c 100644
--- a/smart_contracts/ethereum/solidity_firefly/package-lock.json
+++ b/smart_contracts/ethereum/solidity_firefly/package-lock.json
@@ -566,29 +566,7 @@
"@ethersproject/transactions": "^5.7.0",
"@ethersproject/web": "^5.7.0",
"bech32": "1.1.4",
- "ws": "7.4.6"
- }
- },
- "node_modules/@ethersproject/providers/node_modules/ws": {
- "version": "7.4.6",
- "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
- "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==",
- "dev": true,
- "peer": true,
- "engines": {
- "node": ">=8.3.0"
- },
- "peerDependencies": {
- "bufferutil": "^4.0.1",
- "utf-8-validate": "^5.0.2"
- },
- "peerDependenciesMeta": {
- "bufferutil": {
- "optional": true
- },
- "utf-8-validate": {
- "optional": true
- }
+ "ws": "7.5.10"
}
},
"node_modules/@ethersproject/random": {
@@ -676,10 +654,33 @@
"@ethersproject/logger": "^5.7.0",
"@ethersproject/properties": "^5.7.0",
"bn.js": "^5.2.1",
- "elliptic": "6.5.4",
+ "elliptic": "6.6.1",
"hash.js": "1.1.7"
}
},
+ "node_modules/@ethersproject/signing-key/node_modules/elliptic": {
+ "version": "6.6.1",
+ "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz",
+ "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "bn.js": "^4.11.9",
+ "brorand": "^1.1.0",
+ "hash.js": "^1.0.0",
+ "hmac-drbg": "^1.0.1",
+ "inherits": "^2.0.4",
+ "minimalistic-assert": "^1.0.1",
+ "minimalistic-crypto-utils": "^1.0.1"
+ }
+ },
+ "node_modules/@ethersproject/signing-key/node_modules/elliptic/node_modules/bn.js": {
+ "version": "4.12.1",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz",
+ "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==",
+ "dev": true,
+ "peer": true
+ },
"node_modules/@ethersproject/solidity": {
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz",
@@ -1025,174 +1026,89 @@
}
},
"node_modules/@nomicfoundation/edr": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.3.2.tgz",
- "integrity": "sha512-HGWtjibAK1mo4I2A7nJ/fXqe/J9G54OrSPJnnkY2K8TiXotYLShGd9GvHkae3PuFjTJKm6ZgBy7tveJj5yrCfw==",
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.7.0.tgz",
+ "integrity": "sha512-+Zyu7TE47TGNcPhOfWLPA/zISs32WDMXrhSWdWYyPHDVn/Uux5TVuOeScKb0BR/R8EJ+leR8COUF/EGxvDOVKg==",
"dev": true,
"peer": true,
+ "dependencies": {
+ "@nomicfoundation/edr-darwin-arm64": "0.7.0",
+ "@nomicfoundation/edr-darwin-x64": "0.7.0",
+ "@nomicfoundation/edr-linux-arm64-gnu": "0.7.0",
+ "@nomicfoundation/edr-linux-arm64-musl": "0.7.0",
+ "@nomicfoundation/edr-linux-x64-gnu": "0.7.0",
+ "@nomicfoundation/edr-linux-x64-musl": "0.7.0",
+ "@nomicfoundation/edr-win32-x64-msvc": "0.7.0"
+ },
"engines": {
"node": ">= 18"
- },
- "optionalDependencies": {
- "@nomicfoundation/edr-darwin-arm64": "0.3.2",
- "@nomicfoundation/edr-darwin-x64": "0.3.2",
- "@nomicfoundation/edr-linux-arm64-gnu": "0.3.2",
- "@nomicfoundation/edr-linux-arm64-musl": "0.3.2",
- "@nomicfoundation/edr-linux-x64-gnu": "0.3.2",
- "@nomicfoundation/edr-linux-x64-musl": "0.3.2",
- "@nomicfoundation/edr-win32-arm64-msvc": "0.3.2",
- "@nomicfoundation/edr-win32-ia32-msvc": "0.3.2",
- "@nomicfoundation/edr-win32-x64-msvc": "0.3.2"
}
},
"node_modules/@nomicfoundation/edr-darwin-arm64": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.3.2.tgz",
- "integrity": "sha512-l6wfSBUUbGJiCENT6272CDI8yoMuf0sZH56H5qz3HnAyVzenkOvmzyF6/lar54m986kdAQqWls4cLvDxiOuLxg==",
- "cpu": [
- "arm64"
- ],
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.7.0.tgz",
+ "integrity": "sha512-vAH20oh4GaSB/iQFTRcoO8jLc0CLd9XuLY9I7vtcqZWAiM4U1J4Y8cu67PWmtxbvUQOqXR7S6FtAr8/AlWm14g==",
"dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
"peer": true,
"engines": {
"node": ">= 18"
}
},
"node_modules/@nomicfoundation/edr-darwin-x64": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.3.2.tgz",
- "integrity": "sha512-OboExL7vEw+TRJQl3KkaEKU4K7PTdZPTInZ0fxMAtOpcWp7EKR+dQo68vc/iAOusB3xszHKxt7t+WpisItfdcg==",
- "cpu": [
- "x64"
- ],
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.7.0.tgz",
+ "integrity": "sha512-WHDdIrPvLlgXQr2eKypBM5xOZAwdxhDAEQIvEMQL8tEEm2qYW2bliUlssBPrs8E3bdivFbe1HizImslMAfU3+g==",
"dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
"peer": true,
"engines": {
"node": ">= 18"
}
},
"node_modules/@nomicfoundation/edr-linux-arm64-gnu": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.3.2.tgz",
- "integrity": "sha512-xtEK+1eg++3pHi6405NDXd80S3CGOFEGQIyVGCwjMGQFOLSzBGGCsrb/0GB4J19zd1o/8ftCd/HjZcbVAWWTLQ==",
- "cpu": [
- "arm64"
- ],
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.7.0.tgz",
+ "integrity": "sha512-WXpJB54ukz1no7gxCPXVEw9pgl/9UZ/WO3l1ctyv/T7vOygjqA4SUd6kppTs6MNXAuTiisPtvJ/fmvHiMBLrsw==",
"dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
"peer": true,
"engines": {
"node": ">= 18"
}
},
"node_modules/@nomicfoundation/edr-linux-arm64-musl": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.3.2.tgz",
- "integrity": "sha512-3cIsskJOXQ1yEVsImmCacY7O03tUTiWrmd54F05PnPFrDLkjbzodQ3b2gUWzfbzUZWl67ZTJd1CvVSzpe7XGzw==",
- "cpu": [
- "arm64"
- ],
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.7.0.tgz",
+ "integrity": "sha512-1iZYOcEgc+zJI7JQrlAFziuy9sBz1WgnIx3HIIu0J7lBRZ/AXeHHgATb+4InqxtEx9O3W8A0s7f11SyFqJL4Aw==",
"dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
"peer": true,
"engines": {
"node": ">= 18"
}
},
"node_modules/@nomicfoundation/edr-linux-x64-gnu": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.3.2.tgz",
- "integrity": "sha512-ouPdphHNsyO7wqwa4hwahC5WqBglK/fIvMmhR/SXNZ9qruIpsA8ZZKIURaHMOv/2h2BbNGcyTX9uEk6+5rK/MQ==",
- "cpu": [
- "x64"
- ],
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.7.0.tgz",
+ "integrity": "sha512-wSjC94WcR5MM8sg9w3OsAmT6+bbmChJw6uJKoXR3qscps/jdhjzJWzfgT0XGRq3XMUfimyafW2RWOyfX3ouhrQ==",
"dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
"peer": true,
"engines": {
"node": ">= 18"
}
},
"node_modules/@nomicfoundation/edr-linux-x64-musl": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.3.2.tgz",
- "integrity": "sha512-sRhwhiPbkpJMOUwXW1FZw9ks6xWyQhIhM0E8o3TXEXKSPKTE6whQLEk1R37iFITaI36vb6rSwLKTU1cb32gCoA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "peer": true,
- "engines": {
- "node": ">= 18"
- }
- },
- "node_modules/@nomicfoundation/edr-win32-arm64-msvc": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-arm64-msvc/-/edr-win32-arm64-msvc-0.3.2.tgz",
- "integrity": "sha512-IEwVealKfumu1HSSnama26yPuQC/uthRPK5IWtFsQUOGwOXaS1r9Bu7cGYH2jBHl3IT/JbxD4xzPq/2pM9uK0A==",
- "cpu": [
- "arm64"
- ],
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.7.0.tgz",
+ "integrity": "sha512-Us22+AZ7wkG1mZwxqE4S4ZcuwkEA5VrUiBOJSvKHGOgy6vFvB/Euh5Lkp4GovwjrtiXuvyGO2UmtkzymZKDxZw==",
"dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "peer": true,
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@nomicfoundation/edr-win32-ia32-msvc": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-ia32-msvc/-/edr-win32-ia32-msvc-0.3.2.tgz",
- "integrity": "sha512-jYMnf6SFgguqROswwdsjJ1wvneD/5c16pVu9OD4DxNqhKNP5bHEw6L2N4DcJ89tpXMpJ6AlOpc0QuwzddiZ3tA==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
"peer": true,
"engines": {
"node": ">= 18"
}
},
"node_modules/@nomicfoundation/edr-win32-x64-msvc": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.3.2.tgz",
- "integrity": "sha512-Byn4QuWczRy/DUUQM3WjglgX/jGVUURVFaUsmIhnGg//MPlCLawubBGRqsrMuvaYedlIIJ4I2rgKvZlxdgHrqg==",
- "cpu": [
- "x64"
- ],
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.7.0.tgz",
+ "integrity": "sha512-HAry0heTsWkzReVtjHwoIq3BgFCvXpVhJ5qPmTnegZGsr/KxqvMmHyDMifzKao4bycU8yrpTSyOiAJt27RWjzQ==",
"dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
"peer": true,
"engines": {
"node": ">= 18"
@@ -1268,9 +1184,9 @@
}
},
"node_modules/@nomicfoundation/hardhat-chai-matchers": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-2.0.6.tgz",
- "integrity": "sha512-Te1Uyo9oJcTCF0Jy9dztaLpshmlpjLf2yPtWXlXuLjMt3RRSmJLm/+rKVTW6gfadAEs12U/it6D0ZRnnRGiICQ==",
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-2.0.8.tgz",
+ "integrity": "sha512-Z5PiCXH4xhNLASROlSUOADfhfpfhYO6D7Hn9xp8PddmHey0jq704cr6kfU8TRrQ4PUZbpfsZadPj+pCfZdjPIg==",
"dev": true,
"peer": true,
"dependencies": {
@@ -1287,9 +1203,9 @@
}
},
"node_modules/@nomicfoundation/hardhat-ethers": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-3.0.5.tgz",
- "integrity": "sha512-RNFe8OtbZK6Ila9kIlHp0+S80/0Bu/3p41HUpaRIoHLm6X3WekTd83vob3rE54Duufu1edCiBDxspBzi2rxHHw==",
+ "version": "3.0.8",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-3.0.8.tgz",
+ "integrity": "sha512-zhOZ4hdRORls31DTOqg+GmEZM0ujly8GGIuRY7t7szEk2zW/arY1qDug/py8AEktT00v5K+b6RvbVog+va51IA==",
"dev": true,
"peer": true,
"dependencies": {
@@ -1302,17 +1218,18 @@
}
},
"node_modules/@nomicfoundation/hardhat-ignition": {
- "version": "0.15.0",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition/-/hardhat-ignition-0.15.0.tgz",
- "integrity": "sha512-GbAe90O22uM67U/JnffXX+mBMn0HqCKSH+D98Tb5uWqR1N/M00cB3yY8OdqzVai7I6SuIKTc91mPdvtWt8R3MA==",
+ "version": "0.15.9",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition/-/hardhat-ignition-0.15.9.tgz",
+ "integrity": "sha512-lSWqhaDOBt6gsqMadkRLvH6HdoFV1v8/bx7z+12cghaOloVwwn48CPoTH2iXXnkqilPGw8rdH5eVTE6UM+2v6Q==",
"dev": true,
"peer": true,
"dependencies": {
- "@nomicfoundation/ignition-core": "^0.15.0",
- "@nomicfoundation/ignition-ui": "^0.15.0",
+ "@nomicfoundation/ignition-core": "^0.15.9",
+ "@nomicfoundation/ignition-ui": "^0.15.9",
"chalk": "^4.0.0",
"debug": "^4.3.2",
"fs-extra": "^10.0.0",
+ "json5": "^2.2.3",
"prompts": "^2.4.2"
},
"peerDependencies": {
@@ -1321,23 +1238,23 @@
}
},
"node_modules/@nomicfoundation/hardhat-ignition-ethers": {
- "version": "0.15.0",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition-ethers/-/hardhat-ignition-ethers-0.15.0.tgz",
- "integrity": "sha512-KmMNUc/jptfwdPA9ukQf+Ajon+m2vLBjDL2ze7d/vQdrS+fDxmoVwmbbEk4GOjianZcwgQOWD9dEWaj04QiowA==",
+ "version": "0.15.9",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition-ethers/-/hardhat-ignition-ethers-0.15.9.tgz",
+ "integrity": "sha512-9PwwgLv3z2ec3B26mK0IjiFezHFFBcBcs1qKaRu8SanARE4b7RvrfiLIy8ZXE7HaxgPt32kSsQzehhzAwAIj1Q==",
"dev": true,
"peer": true,
"peerDependencies": {
"@nomicfoundation/hardhat-ethers": "^3.0.4",
- "@nomicfoundation/hardhat-ignition": "^0.15.0",
- "@nomicfoundation/ignition-core": "^0.15.0",
+ "@nomicfoundation/hardhat-ignition": "^0.15.9",
+ "@nomicfoundation/ignition-core": "^0.15.9",
"ethers": "^6.7.0",
"hardhat": "^2.18.0"
}
},
"node_modules/@nomicfoundation/hardhat-network-helpers": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.10.tgz",
- "integrity": "sha512-R35/BMBlx7tWN5V6d/8/19QCwEmIdbnA4ZrsuXgvs8i2qFx5i7h6mH5pBS4Pwi4WigLH+upl6faYusrNPuzMrQ==",
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.12.tgz",
+ "integrity": "sha512-xTNQNI/9xkHvjmCJnJOTyqDSl8uq1rKb2WOVmixQxFtRd7Oa3ecO8zM0cyC2YmOK+jHB9WPZ+F/ijkHg1CoORA==",
"dev": true,
"peer": true,
"dependencies": {
@@ -1374,18 +1291,18 @@
}
},
"node_modules/@nomicfoundation/hardhat-verify": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.0.5.tgz",
- "integrity": "sha512-Tg4zu8RkWpyADSFIgF4FlJIUEI4VkxcvELsmbJn2OokbvH2SnUrqKmw0BBfDrtvP0hhmx8wsnrRKP5DV/oTyTA==",
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.0.12.tgz",
+ "integrity": "sha512-Lg3Nu7DCXASQRVI/YysjuAX2z8jwOCbS0w5tz2HalWGSTZThqA0v9N0v0psHbKNqzPJa8bNOeapIVSziyJTnAg==",
"dev": true,
"peer": true,
"dependencies": {
"@ethersproject/abi": "^5.1.2",
"@ethersproject/address": "^5.0.2",
"cbor": "^8.1.0",
- "chalk": "^2.4.2",
"debug": "^4.1.1",
"lodash.clonedeep": "^4.5.0",
+ "picocolors": "^1.1.0",
"semver": "^6.3.0",
"table": "^6.8.0",
"undici": "^5.14.0"
@@ -1394,92 +1311,15 @@
"hardhat": "^2.0.4"
}
},
- "node_modules/@nomicfoundation/hardhat-verify/node_modules/ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "color-convert": "^1.9.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@nomicfoundation/hardhat-verify/node_modules/chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@nomicfoundation/hardhat-verify/node_modules/color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "color-name": "1.1.3"
- }
- },
- "node_modules/@nomicfoundation/hardhat-verify/node_modules/color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
- "dev": true,
- "peer": true
- },
- "node_modules/@nomicfoundation/hardhat-verify/node_modules/escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "dev": true,
- "peer": true,
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/@nomicfoundation/hardhat-verify/node_modules/has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "dev": true,
- "peer": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@nomicfoundation/hardhat-verify/node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/@nomicfoundation/ignition-core": {
- "version": "0.15.0",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-core/-/ignition-core-0.15.0.tgz",
- "integrity": "sha512-d/h8jgJHY4xIroHqdaGeTkTqjQeuzmU759AOn1Fg88cuxVhS7JM22ZI0bQWyLNSMsVstHBIo+lSMIsvm9jBF2w==",
+ "version": "0.15.9",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-core/-/ignition-core-0.15.9.tgz",
+ "integrity": "sha512-X8W+7UP/UQPorpHUnGvA1OdsEr/edGi8tDpNwEqzaLm83FMZVbRWdOsr3vNICHN2XMzNY/xIm18Cx7xGKL2PQw==",
"dev": true,
"peer": true,
"dependencies": {
"@ethersproject/address": "5.6.1",
+ "@nomicfoundation/solidity-analyzer": "^0.1.1",
"cbor": "^9.0.0",
"debug": "^4.3.2",
"ethers": "^6.7.0",
@@ -1527,9 +1367,9 @@
}
},
"node_modules/@nomicfoundation/ignition-ui": {
- "version": "0.15.0",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-ui/-/ignition-ui-0.15.0.tgz",
- "integrity": "sha512-RBvvQ0e8RcEc/LoSzNTPVKZZ5vEwlmxt7PXG278+6DqCrOqxqmh6W9PtK/4mwwvnTeBqds+8j81jDf6vJbOVBQ==",
+ "version": "0.15.9",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-ui/-/ignition-ui-0.15.9.tgz",
+ "integrity": "sha512-8lzbT7gpJ5PoowPQDQilkwdyqBviUKDMoHp/5rhgnwG1bDslnCS+Lxuo6s9R2akWu9LtEL14dNyqQb6WsURTag==",
"dev": true,
"peer": true
},
@@ -1870,7 +1710,7 @@
"@sentry/tracing": "5.30.0",
"@sentry/types": "5.30.0",
"@sentry/utils": "5.30.0",
- "cookie": "^0.4.1",
+ "cookie": "^1.0.2",
"https-proxy-agent": "^5.0.0",
"lru_map": "^0.3.3",
"tslib": "^1.9.3"
@@ -1879,6 +1719,16 @@
"node": ">=6"
}
},
+ "node_modules/@sentry/node/node_modules/cookie": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
+ "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/@sentry/node/node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
@@ -2107,13 +1957,13 @@
"peer": true
},
"node_modules/@types/node": {
- "version": "20.11.28",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.28.tgz",
- "integrity": "sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==",
+ "version": "22.7.5",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz",
+ "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==",
"dev": true,
"peer": true,
"dependencies": {
- "undici-types": "~5.26.4"
+ "undici-types": "~6.19.2"
}
},
"node_modules/@types/pbkdf2": {
@@ -2431,9 +2281,9 @@
}
},
"node_modules/axios": {
- "version": "1.6.8",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz",
- "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==",
+ "version": "1.7.9",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
+ "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
"dev": true,
"peer": true,
"dependencies": {
@@ -2541,13 +2391,13 @@
}
},
"node_modules/braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"peer": true,
"dependencies": {
- "fill-range": "^7.0.1"
+ "fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
@@ -2754,28 +2604,33 @@
}
},
"node_modules/chokidar": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
- "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+ "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
"dev": true,
"peer": true,
"dependencies": {
- "anymatch": "~3.1.2",
- "braces": "~3.0.2",
- "glob-parent": "~5.1.2",
- "is-binary-path": "~2.1.0",
- "is-glob": "~4.0.1",
- "normalize-path": "~3.0.0",
- "readdirp": "~3.6.0"
+ "readdirp": "^4.0.1"
},
"engines": {
- "node": ">= 8.10.0"
+ "node": ">= 14.16.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/chokidar/node_modules/readdirp": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
+ "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">= 14.18.0"
},
- "optionalDependencies": {
- "fsevents": "~2.3.2"
+ "funding": {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
}
},
"node_modules/ci-info": {
@@ -3076,11 +2931,14 @@
}
},
"node_modules/commander": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz",
- "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==",
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
+ "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
"dev": true,
- "peer": true
+ "peer": true,
+ "engines": {
+ "node": ">= 12"
+ }
},
"node_modules/concat-map": {
"version": "0.0.1",
@@ -3138,16 +2996,6 @@
"safe-buffer": "~5.1.0"
}
},
- "node_modules/cookie": {
- "version": "0.4.2",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
- "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
- "dev": true,
- "peer": true,
- "engines": {
- "node": ">= 0.6"
- }
- },
"node_modules/core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
@@ -3209,13 +3057,13 @@
"peer": true
},
"node_modules/debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+ "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"dev": true,
"peer": true,
"dependencies": {
- "ms": "2.1.2"
+ "ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
@@ -3308,9 +3156,9 @@
}
},
"node_modules/diff": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
- "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz",
+ "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==",
"dev": true,
"peer": true,
"engines": {
@@ -3344,9 +3192,9 @@
}
},
"node_modules/elliptic": {
- "version": "6.5.4",
- "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
- "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
+ "version": "6.6.1",
+ "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz",
+ "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==",
"dev": true,
"peer": true,
"dependencies": {
@@ -3712,7 +3560,7 @@
"@types/bn.js": "^4.11.3",
"bn.js": "^4.11.0",
"create-hash": "^1.1.2",
- "elliptic": "^6.5.2",
+ "elliptic": "^6.6.1",
"ethereum-cryptography": "^0.1.3",
"ethjs-util": "0.1.6",
"rlp": "^2.2.3"
@@ -3736,9 +3584,9 @@
}
},
"node_modules/ethers": {
- "version": "6.11.1",
- "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.11.1.tgz",
- "integrity": "sha512-mxTAE6wqJQAbp5QAe/+o+rXOID7Nw91OZXvgpjDa1r4fAbq2Nu314oEZSbjoRLacuCzs7kUC3clEvkCQowffGg==",
+ "version": "6.13.5",
+ "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.13.5.tgz",
+ "integrity": "sha512-+knKNieu5EKRThQJWwqaJ10a6HE9sSehGeqWN65//wE7j47ZpFhKAnHB/JJFibwwg61I/koxaPsXbXpD/skNOQ==",
"dev": true,
"funding": [
{
@@ -3755,36 +3603,51 @@
"@adraffy/ens-normalize": "1.10.1",
"@noble/curves": "1.2.0",
"@noble/hashes": "1.3.2",
- "@types/node": "18.15.13",
+ "@types/node": "22.7.5",
"aes-js": "4.0.0-beta.5",
- "tslib": "2.4.0",
- "ws": "8.5.0"
+ "tslib": "2.7.0",
+ "ws": "8.17.1"
},
"engines": {
"node": ">=14.0.0"
}
},
- "node_modules/ethers/node_modules/@types/node": {
- "version": "18.15.13",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz",
- "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==",
- "dev": true,
- "peer": true
- },
- "node_modules/ethjs-unit": {
- "version": "0.1.6",
- "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz",
- "integrity": "sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==",
+ "node_modules/ethers/node_modules/ws": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
+ "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"dev": true,
"peer": true,
- "dependencies": {
- "bn.js": "4.11.6",
- "number-to-bn": "1.7.0"
- },
"engines": {
- "node": ">=6.5.0",
- "npm": ">=3"
- }
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ethjs-unit": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz",
+ "integrity": "sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "bn.js": "4.11.6",
+ "number-to-bn": "1.7.0"
+ },
+ "engines": {
+ "node": ">=6.5.0",
+ "npm": ">=3"
+ }
},
"node_modules/ethjs-unit/node_modules/bn.js": {
"version": "4.11.6",
@@ -3861,9 +3724,9 @@
}
},
"node_modules/fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"peer": true,
"dependencies": {
@@ -3887,16 +3750,20 @@
}
},
"node_modules/find-up": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
- "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
"dev": true,
"peer": true,
"dependencies": {
- "locate-path": "^2.0.0"
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
},
"engines": {
- "node": ">=4"
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/flat": {
@@ -4283,15 +4150,15 @@
}
},
"node_modules/hardhat": {
- "version": "2.22.1",
- "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.1.tgz",
- "integrity": "sha512-cTWYIJc5jQ132XUI8oRI/TO9L6oavPoJRCTRU9sIjkVxvkxz0Axz0K83Z3BEdJTqBQ2W84ZRoTekti84kBwCjg==",
+ "version": "2.22.18",
+ "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.18.tgz",
+ "integrity": "sha512-2+kUz39gvMo56s75cfLBhiFedkQf+gXdrwCcz4R/5wW0oBdwiyfj2q9BIkMoaA0WIGYYMU2I1Cc4ucTunhfjzw==",
"dev": true,
"peer": true,
"dependencies": {
"@ethersproject/abi": "^5.1.2",
"@metamask/eth-sig-util": "^4.0.0",
- "@nomicfoundation/edr": "^0.3.1",
+ "@nomicfoundation/edr": "^0.7.0",
"@nomicfoundation/ethereumjs-common": "4.0.4",
"@nomicfoundation/ethereumjs-tx": "5.0.4",
"@nomicfoundation/ethereumjs-util": "9.0.4",
@@ -4303,35 +4170,36 @@
"aggregate-error": "^3.0.0",
"ansi-escapes": "^4.3.0",
"boxen": "^5.1.2",
- "chalk": "^2.4.2",
- "chokidar": "^3.4.0",
+ "chokidar": "^4.0.0",
"ci-info": "^2.0.0",
"debug": "^4.1.1",
"enquirer": "^2.3.0",
"env-paths": "^2.2.0",
"ethereum-cryptography": "^1.0.3",
"ethereumjs-abi": "^0.6.8",
- "find-up": "^2.1.0",
+ "find-up": "^5.0.0",
"fp-ts": "1.19.3",
"fs-extra": "^7.0.1",
- "glob": "7.2.0",
"immutable": "^4.0.0-rc.12",
"io-ts": "1.10.4",
+ "json-stream-stringify": "^3.1.4",
"keccak": "^3.0.2",
"lodash": "^4.17.11",
"mnemonist": "^0.38.0",
"mocha": "^10.0.0",
"p-map": "^4.0.0",
+ "picocolors": "^1.1.0",
"raw-body": "^2.4.1",
"resolve": "1.17.0",
"semver": "^6.3.0",
- "solc": "0.7.3",
+ "solc": "0.8.26",
"source-map-support": "^0.5.13",
"stacktrace-parser": "^0.1.10",
+ "tinyglobby": "^0.2.6",
"tsort": "0.0.1",
"undici": "^5.14.0",
"uuid": "^8.3.2",
- "ws": "^7.4.6"
+ "ws": "^7.5.10"
},
"bin": {
"hardhat": "internal/cli/bootstrap.js"
@@ -4412,61 +4280,6 @@
"@scure/base": "~1.1.0"
}
},
- "node_modules/hardhat/node_modules/ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "color-convert": "^1.9.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/hardhat/node_modules/chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/hardhat/node_modules/color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "color-name": "1.1.3"
- }
- },
- "node_modules/hardhat/node_modules/color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
- "dev": true,
- "peer": true
- },
- "node_modules/hardhat/node_modules/escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "dev": true,
- "peer": true,
- "engines": {
- "node": ">=0.8.0"
- }
- },
"node_modules/hardhat/node_modules/ethereum-cryptography": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz",
@@ -4495,16 +4308,6 @@
"node": ">=6 <7 || >=8"
}
},
- "node_modules/hardhat/node_modules/has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "dev": true,
- "peer": true,
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/hardhat/node_modules/jsonfile": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
@@ -4515,19 +4318,6 @@
"graceful-fs": "^4.1.6"
}
},
- "node_modules/hardhat/node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/hardhat/node_modules/universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
@@ -4538,28 +4328,6 @@
"node": ">= 4.0.0"
}
},
- "node_modules/hardhat/node_modules/ws": {
- "version": "7.5.9",
- "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
- "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
- "dev": true,
- "peer": true,
- "engines": {
- "node": ">=8.3.0"
- },
- "peerDependencies": {
- "bufferutil": "^4.0.1",
- "utf-8-validate": "^5.0.2"
- },
- "peerDependenciesMeta": {
- "bufferutil": {
- "optional": true
- },
- "utf-8-validate": {
- "optional": true
- }
- }
- },
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -4968,6 +4736,16 @@
"dev": true,
"peer": true
},
+ "node_modules/json-stream-stringify": {
+ "version": "3.1.6",
+ "resolved": "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-3.1.6.tgz",
+ "integrity": "sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=7.10.1"
+ }
+ },
"node_modules/json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
@@ -4975,6 +4753,19 @@
"dev": true,
"peer": true
},
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "peer": true,
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/jsonfile": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
@@ -5024,16 +4815,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/klaw": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz",
- "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==",
- "dev": true,
- "peer": true,
- "optionalDependencies": {
- "graceful-fs": "^4.1.9"
- }
- },
"node_modules/kleur": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
@@ -5059,17 +4840,19 @@
}
},
"node_modules/locate-path": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
- "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
"dev": true,
"peer": true,
"dependencies": {
- "p-locate": "^2.0.0",
- "path-exists": "^3.0.0"
+ "p-locate": "^5.0.0"
},
"engines": {
- "node": ">=4"
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/lodash": {
@@ -5208,13 +4991,13 @@
"peer": true
},
"node_modules/micromatch": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
- "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true,
"peer": true,
"dependencies": {
- "braces": "^3.0.2",
+ "braces": "^3.0.3",
"picomatch": "^2.3.1"
},
"engines": {
@@ -5305,32 +5088,32 @@
}
},
"node_modules/mocha": {
- "version": "10.3.0",
- "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.3.0.tgz",
- "integrity": "sha512-uF2XJs+7xSLsrmIvn37i/wnc91nw7XjOQB8ccyx5aEgdnohr7n+rEiZP23WkCYHjilR6+EboEnbq/ZQDz4LSbg==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "ansi-colors": "4.1.1",
- "browser-stdout": "1.3.1",
- "chokidar": "3.5.3",
- "debug": "4.3.4",
- "diff": "5.0.0",
- "escape-string-regexp": "4.0.0",
- "find-up": "5.0.0",
- "glob": "8.1.0",
- "he": "1.2.0",
- "js-yaml": "4.1.0",
- "log-symbols": "4.1.0",
- "minimatch": "5.0.1",
- "ms": "2.1.3",
- "serialize-javascript": "6.0.0",
- "strip-json-comments": "3.1.1",
- "supports-color": "8.1.1",
- "workerpool": "6.2.1",
- "yargs": "16.2.0",
- "yargs-parser": "20.2.4",
- "yargs-unparser": "2.0.0"
+ "version": "10.8.2",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz",
+ "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "ansi-colors": "^4.1.3",
+ "browser-stdout": "^1.3.1",
+ "chokidar": "^3.5.3",
+ "debug": "^4.3.5",
+ "diff": "^5.2.0",
+ "escape-string-regexp": "^4.0.0",
+ "find-up": "^5.0.0",
+ "glob": "^8.1.0",
+ "he": "^1.2.0",
+ "js-yaml": "^4.1.0",
+ "log-symbols": "^4.1.0",
+ "minimatch": "^5.1.6",
+ "ms": "^2.1.3",
+ "serialize-javascript": "^6.0.2",
+ "strip-json-comments": "^3.1.1",
+ "supports-color": "^8.1.1",
+ "workerpool": "^6.5.1",
+ "yargs": "^16.2.0",
+ "yargs-parser": "^20.2.9",
+ "yargs-unparser": "^2.0.0"
},
"bin": {
"_mocha": "bin/_mocha",
@@ -5340,16 +5123,6 @@
"node": ">= 14.0.0"
}
},
- "node_modules/mocha/node_modules/ansi-colors": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
- "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
- "dev": true,
- "peer": true,
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/mocha/node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
@@ -5388,23 +5161,6 @@
"fsevents": "~2.3.2"
}
},
- "node_modules/mocha/node_modules/find-up": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
- "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "locate-path": "^6.0.0",
- "path-exists": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/mocha/node_modules/glob": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
@@ -5425,26 +5181,10 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/mocha/node_modules/locate-path": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
- "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "p-locate": "^5.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/mocha/node_modules/minimatch": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
- "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
"dev": true,
"peer": true,
"dependencies": {
@@ -5454,55 +5194,6 @@
"node": ">=10"
}
},
- "node_modules/mocha/node_modules/ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
- "dev": true,
- "peer": true
- },
- "node_modules/mocha/node_modules/p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "yocto-queue": "^0.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/mocha/node_modules/p-locate": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
- "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "p-limit": "^3.0.2"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/mocha/node_modules/path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true,
- "peer": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/mocha/node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
@@ -5520,9 +5211,9 @@
}
},
"node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true,
"peer": true
},
@@ -5710,29 +5401,35 @@
}
},
"node_modules/p-limit": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
- "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
"dev": true,
"peer": true,
"dependencies": {
- "p-try": "^1.0.0"
+ "yocto-queue": "^0.1.0"
},
"engines": {
- "node": ">=4"
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-locate": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
- "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
"dev": true,
"peer": true,
"dependencies": {
- "p-limit": "^1.1.0"
+ "p-limit": "^3.0.2"
},
"engines": {
- "node": ">=4"
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-map": {
@@ -5751,16 +5448,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/p-try": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
- "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==",
- "dev": true,
- "peer": true,
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/parse-cache-control": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz",
@@ -5769,13 +5456,13 @@
"peer": true
},
"node_modules/path-exists": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
- "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true,
"peer": true,
"engines": {
- "node": ">=4"
+ "node": ">=8"
}
},
"node_modules/path-is-absolute": {
@@ -5832,6 +5519,13 @@
"node": ">=0.12"
}
},
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "peer": true
+ },
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
@@ -6136,19 +5830,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/rimraf": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
- "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "glob": "^7.1.3"
- },
- "bin": {
- "rimraf": "bin.js"
- }
- },
"node_modules/ripemd160": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
@@ -6344,21 +6025,28 @@
"peer": true
},
"node_modules/secp256k1": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz",
- "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.4.tgz",
+ "integrity": "sha512-6JfvwvjUOn8F/jUoBY2Q1v5WY5XS+rj8qSe0v8Y4ezH4InLgTEeOOPQsRll9OV429Pvo6BCHGavIyJfr3TAhsw==",
"dev": true,
"hasInstallScript": true,
"peer": true,
"dependencies": {
- "elliptic": "^6.5.4",
- "node-addon-api": "^2.0.0",
+ "elliptic": "^6.6.1",
+ "node-addon-api": "^5.0.0",
"node-gyp-build": "^4.2.0"
},
"engines": {
- "node": ">=10.0.0"
+ "node": ">=18.0.0"
}
},
+ "node_modules/secp256k1/node_modules/node-addon-api": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz",
+ "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==",
+ "dev": true,
+ "peer": true
+ },
"node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
@@ -6370,9 +6058,9 @@
}
},
"node_modules/serialize-javascript": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
- "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
+ "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
"dev": true,
"peer": true,
"dependencies": {
@@ -6512,51 +6200,25 @@
}
},
"node_modules/solc": {
- "version": "0.7.3",
- "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz",
- "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==",
+ "version": "0.8.26",
+ "resolved": "https://registry.npmjs.org/solc/-/solc-0.8.26.tgz",
+ "integrity": "sha512-yiPQNVf5rBFHwN6SIf3TUUvVAFKcQqmSUFeq+fb6pNRCo0ZCgpYOZDi3BVoezCPIAcKrVYd/qXlBLUP9wVrZ9g==",
"dev": true,
"peer": true,
"dependencies": {
"command-exists": "^1.2.8",
- "commander": "3.0.2",
+ "commander": "^8.1.0",
"follow-redirects": "^1.12.1",
- "fs-extra": "^0.30.0",
"js-sha3": "0.8.0",
"memorystream": "^0.3.1",
- "require-from-string": "^2.0.0",
"semver": "^5.5.0",
"tmp": "0.0.33"
},
"bin": {
- "solcjs": "solcjs"
+ "solcjs": "solc.js"
},
"engines": {
- "node": ">=8.0.0"
- }
- },
- "node_modules/solc/node_modules/fs-extra": {
- "version": "0.30.0",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz",
- "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==",
- "dev": true,
- "peer": true,
- "dependencies": {
- "graceful-fs": "^4.1.2",
- "jsonfile": "^2.1.0",
- "klaw": "^1.0.0",
- "path-is-absolute": "^1.0.0",
- "rimraf": "^2.2.8"
- }
- },
- "node_modules/solc/node_modules/jsonfile": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
- "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==",
- "dev": true,
- "peer": true,
- "optionalDependencies": {
- "graceful-fs": "^4.1.6"
+ "node": ">=10.0.0"
}
},
"node_modules/solc/node_modules/semver": {
@@ -6570,14 +6232,14 @@
}
},
"node_modules/solidity-coverage": {
- "version": "0.8.11",
- "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.11.tgz",
- "integrity": "sha512-yy0Yk+olovBbXn0Me8BWULmmv7A69ZKkP5aTOJGOO8u61Tu2zS989erfjtFlUjDnfWtxRAVkd8BsQD704yLWHw==",
+ "version": "0.8.14",
+ "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.14.tgz",
+ "integrity": "sha512-ItAAObe5GaEOp20kXC2BZRnph+9P7Rtoqg2mQc2SXGEHgSDF2wWd1Wxz3ntzQWXkbCtIIGdJT918HG00cObwbA==",
"dev": true,
"peer": true,
"dependencies": {
"@ethersproject/abi": "^5.0.9",
- "@solidity-parser/parser": "^0.18.0",
+ "@solidity-parser/parser": "^0.19.0",
"chalk": "^2.4.2",
"death": "^1.1.0",
"difflib": "^0.2.4",
@@ -6586,7 +6248,7 @@
"global-modules": "^2.0.0",
"globby": "^10.0.1",
"jsonschema": "^1.2.4",
- "lodash": "^4.17.15",
+ "lodash": "^4.17.21",
"mocha": "^10.2.0",
"node-emoji": "^1.10.0",
"pify": "^4.0.1",
@@ -6604,9 +6266,9 @@
}
},
"node_modules/solidity-coverage/node_modules/@solidity-parser/parser": {
- "version": "0.18.0",
- "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.18.0.tgz",
- "integrity": "sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA==",
+ "version": "0.19.0",
+ "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.19.0.tgz",
+ "integrity": "sha512-RV16k/qIxW/wWc+mLzV3ARyKUaMUTBy9tOLMzFhtNSKYeTAanQ3a5MudJKf/8arIFnA2L27SNjarQKmFg0w/jA==",
"dev": true,
"peer": true
},
@@ -7042,6 +6704,51 @@
"readable-stream": "3"
}
},
+ "node_modules/tinyglobby": {
+ "version": "0.2.11",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.11.tgz",
+ "integrity": "sha512-32TmKeeKUahv0Go8WmQgiEp9Y21NuxjwjqiRC1nrUB51YacfSwuB44xgXD+HdIppmMRgjQNPdrHyA6vIybYZ+g==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "fdir": "^6.4.3",
+ "picomatch": "^4.0.2"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/tinyglobby/node_modules/fdir": {
+ "version": "6.4.3",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz",
+ "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==",
+ "dev": true,
+ "peer": true,
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tinyglobby/node_modules/picomatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
+ "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
"node_modules/tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@@ -7159,9 +6866,9 @@
}
},
"node_modules/tslib": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
- "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
+ "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",
"dev": true,
"peer": true
},
@@ -7361,9 +7068,9 @@
}
},
"node_modules/undici": {
- "version": "5.28.3",
- "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz",
- "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==",
+ "version": "5.28.5",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.5.tgz",
+ "integrity": "sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==",
"dev": true,
"peer": true,
"dependencies": {
@@ -7374,9 +7081,9 @@
}
},
"node_modules/undici-types": {
- "version": "5.26.5",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
- "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+ "version": "6.19.8",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
+ "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"dev": true,
"peer": true
},
@@ -7568,9 +7275,9 @@
}
},
"node_modules/workerpool": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
- "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz",
+ "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==",
"dev": true,
"peer": true
},
@@ -7600,13 +7307,13 @@
"peer": true
},
"node_modules/ws": {
- "version": "8.5.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz",
- "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==",
+ "version": "7.5.10",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
+ "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"dev": true,
"peer": true,
"engines": {
- "node": ">=10.0.0"
+ "node": ">=8.3.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
@@ -7658,9 +7365,9 @@
}
},
"node_modules/yargs-parser": {
- "version": "20.2.4",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
- "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
+ "version": "20.2.9",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+ "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
"dev": true,
"peer": true,
"engines": {
diff --git a/smart_contracts/fabric/custompin-sample/.gitignore b/smart_contracts/fabric/custompin-sample/.gitignore
index b2a69e9a03..c2bab4fd8e 100644
--- a/smart_contracts/fabric/custompin-sample/.gitignore
+++ b/smart_contracts/fabric/custompin-sample/.gitignore
@@ -1,2 +1,3 @@
.DS_Store
vendor
+custompin_sample
diff --git a/smart_contracts/fabric/custompin-sample/go.mod b/smart_contracts/fabric/custompin-sample/go.mod
index 0c0df215bc..0b65a0d98e 100644
--- a/smart_contracts/fabric/custompin-sample/go.mod
+++ b/smart_contracts/fabric/custompin-sample/go.mod
@@ -7,7 +7,7 @@ require (
github.com/hyperledger/fabric-contract-api-go v1.2.2
github.com/hyperledger/fabric-protos-go v0.3.3
github.com/stretchr/testify v1.8.4
- google.golang.org/protobuf v1.32.0
+ google.golang.org/protobuf v1.33.0
)
require (
@@ -26,16 +26,16 @@ require (
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
- golang.org/x/net v0.20.0 // indirect
- golang.org/x/sys v0.16.0 // indirect
- golang.org/x/text v0.14.0 // indirect
+ golang.org/x/net v0.33.0 // indirect
+ golang.org/x/sys v0.28.0 // indirect
+ golang.org/x/text v0.21.0 // indirect
google.golang.org/grpc v1.61.0 // indirect
)
require (
github.com/golang/protobuf v1.5.3
github.com/josharian/intern v1.0.0 // indirect
- golang.org/x/mod v0.14.0 // indirect
+ golang.org/x/mod v0.17.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/smart_contracts/fabric/custompin-sample/go.sum b/smart_contracts/fabric/custompin-sample/go.sum
index b6c804998d..e63244ad29 100644
--- a/smart_contracts/fabric/custompin-sample/go.sum
+++ b/smart_contracts/fabric/custompin-sample/go.sum
@@ -99,23 +99,23 @@ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
-golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
-golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
+golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
+golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
-golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
-golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe h1:bQnxqljG/wqi4NTXu2+DJ3n7APcEA882QZ1JvhQAq9o=
@@ -124,8 +124,8 @@ google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0=
google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
-google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
diff --git a/smart_contracts/fabric/firefly-go/.gitignore b/smart_contracts/fabric/firefly-go/.gitignore
index b2a69e9a03..a76ee7d820 100644
--- a/smart_contracts/fabric/firefly-go/.gitignore
+++ b/smart_contracts/fabric/firefly-go/.gitignore
@@ -1,2 +1,3 @@
.DS_Store
vendor
+chaincode-go
diff --git a/smart_contracts/fabric/firefly-go/go.mod b/smart_contracts/fabric/firefly-go/go.mod
index 6dee927138..9166a36bd5 100644
--- a/smart_contracts/fabric/firefly-go/go.mod
+++ b/smart_contracts/fabric/firefly-go/go.mod
@@ -8,7 +8,7 @@ require (
github.com/hyperledger/fabric-contract-api-go v1.2.2
github.com/hyperledger/fabric-protos-go v0.3.3
github.com/stretchr/testify v1.8.4
- google.golang.org/protobuf v1.32.0
+ google.golang.org/protobuf v1.33.0
)
require (
@@ -28,10 +28,10 @@ require (
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
- golang.org/x/mod v0.14.0 // indirect
- golang.org/x/net v0.20.0 // indirect
- golang.org/x/sys v0.16.0 // indirect
- golang.org/x/text v0.14.0 // indirect
+ golang.org/x/mod v0.17.0 // indirect
+ golang.org/x/net v0.33.0 // indirect
+ golang.org/x/sys v0.28.0 // indirect
+ golang.org/x/text v0.21.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe // indirect
google.golang.org/grpc v1.61.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
diff --git a/smart_contracts/fabric/firefly-go/go.sum b/smart_contracts/fabric/firefly-go/go.sum
index b6c804998d..e63244ad29 100644
--- a/smart_contracts/fabric/firefly-go/go.sum
+++ b/smart_contracts/fabric/firefly-go/go.sum
@@ -99,23 +99,23 @@ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
-golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
-golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
+golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
+golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
-golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
-golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe h1:bQnxqljG/wqi4NTXu2+DJ3n7APcEA882QZ1JvhQAq9o=
@@ -124,8 +124,8 @@ google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0=
google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
-google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
diff --git a/test/data/contracts/assetcreator/go.mod b/test/data/contracts/assetcreator/go.mod
index 2a9d8cee11..71092bea0f 100644
--- a/test/data/contracts/assetcreator/go.mod
+++ b/test/data/contracts/assetcreator/go.mod
@@ -24,12 +24,12 @@ require (
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
- golang.org/x/mod v0.14.0 // indirect
- golang.org/x/net v0.20.0 // indirect
- golang.org/x/sys v0.16.0 // indirect
- golang.org/x/text v0.14.0 // indirect
+ golang.org/x/mod v0.17.0 // indirect
+ golang.org/x/net v0.33.0 // indirect
+ golang.org/x/sys v0.28.0 // indirect
+ golang.org/x/text v0.21.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe // indirect
google.golang.org/grpc v1.61.0 // indirect
- google.golang.org/protobuf v1.32.0 // indirect
+ google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/test/data/contracts/assetcreator/go.sum b/test/data/contracts/assetcreator/go.sum
index b6c804998d..e63244ad29 100644
--- a/test/data/contracts/assetcreator/go.sum
+++ b/test/data/contracts/assetcreator/go.sum
@@ -99,23 +99,23 @@ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
-golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
-golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
+golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
+golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
-golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
-golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe h1:bQnxqljG/wqi4NTXu2+DJ3n7APcEA882QZ1JvhQAq9o=
@@ -124,8 +124,8 @@ google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0=
google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
-google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
diff --git a/test/e2e/client/restclient.go b/test/e2e/client/restclient.go
index abd5c368a0..cd2fad6d7d 100644
--- a/test/e2e/client/restclient.go
+++ b/test/e2e/client/restclient.go
@@ -370,7 +370,7 @@ func (client *FireFlyClient) GetOrganization(t *testing.T, idOrName string) *cor
SetResult(&identity).
Get(client.namespaced(fmt.Sprintf("%s/%s", urlGetOrganizations, idOrName)))
assert.NoError(t, err)
- if res.StatusCode() == 404 {
+ if res.StatusCode() == http.StatusNotFound {
return nil
}
assert.True(t, res.IsSuccess())
diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go
index 41cfe1658c..c595ad4644 100644
--- a/test/e2e/e2e.go
+++ b/test/e2e/e2e.go
@@ -19,6 +19,7 @@ package e2e
import (
"encoding/json"
"fmt"
+ "net/http"
"os"
"path/filepath"
"strings"
@@ -63,7 +64,7 @@ func PollForUp(t *testing.T, client *client.FireFlyClient) {
var err error
for i := 0; i < 12; i++ {
_, resp, err = client.GetStatus()
- if err == nil && resp.StatusCode() == 200 {
+ if err == nil && resp.StatusCode() == http.StatusOK {
break
}
time.Sleep(5 * time.Second)